summaryrefslogtreecommitdiff
path: root/imdi
diff options
context:
space:
mode:
Diffstat (limited to 'imdi')
-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
28 files changed, 12679 insertions, 0 deletions
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");
+}
+