diff --git a/LICENSE.txt b/LICENSE.txt index cb8d823a1..0de1c6985 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,640 +1,640 @@ - - RawTherapee - - -Copyright ©2004-2012 Gábor Horváth - -RawTherapee is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -RawTherapee is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License below for more details. - - - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - - Copyright ©2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS + + RawTherapee + + +Copyright ©2004-2012 Gábor Horváth + +RawTherapee is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RawTherapee is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License below for more details. + + + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + + Copyright ©2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS diff --git a/rtdata/win/readme.txt b/rtdata/win/readme.txt index f32cdb50a..b20bf104a 100644 --- a/rtdata/win/readme.txt +++ b/rtdata/win/readme.txt @@ -1,14 +1,14 @@ - -INSTALLER SCRIPTS ------------------ - -This "win" directory includes installer setup mechanisms for Windows 32/64. - -As requested in issue 1904 ( http://code.google.com/p/rawtherapee/issues/detail?id=1904 ), -the preferred choice of setup mechanism is Wix widgets. However an InnoSetup script has been -created before the definitive choice and has been added to the source tree, for convenience. - -Once the Wix setup mechanism will be operational, the InnoSetup can be supressed from the source -tree. - + +INSTALLER SCRIPTS +----------------- + +This "win" directory includes installer setup mechanisms for Windows 32/64. + +As requested in issue 1904 ( http://code.google.com/p/rawtherapee/issues/detail?id=1904 ), +the preferred choice of setup mechanism is Wix widgets. However an InnoSetup script has been +created before the definitive choice and has been added to the source tree, for convenience. + +Once the Wix setup mechanism will be operational, the InnoSetup can be supressed from the source +tree. + All discussion about the present document and the setup scripts has to be done in issue 1904. \ No newline at end of file diff --git a/rtengine/EdgePreserveLab.cc b/rtengine/EdgePreserveLab.cc index 967555a94..36cb7d5c3 100644 --- a/rtengine/EdgePreserveLab.cc +++ b/rtengine/EdgePreserveLab.cc @@ -1,229 +1,229 @@ -#include "EdgePreserveLab.h" -#include "boxblur.h" -#include - -#ifdef _OPENMP -#include -#endif - -//#define MAX(a,b) ((a)<(b)?(b):(a)) -//#define MIN(a,b) ((a)>(b)?(b):(a)) - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -EdgePreserveLab::EdgePreserveLab(unsigned int width, unsigned int height){ - w = width; - h = height; - n = w*h; - - //Initialize the matrix just once at construction. - A = new MultiDiagonalSymmetricMatrix(n, 5); - if(!( - A->CreateDiagonal(0, 0) && - A->CreateDiagonal(1, 1) && - A->CreateDiagonal(2, w - 1) && - A->CreateDiagonal(3, w) && - A->CreateDiagonal(4, w + 1))){ - delete A; - A = NULL; - printf("Error in EdgePreserveLab construction: out of memory.\n"); - }else{ - a0 = A->Diagonals[0]; - a_1 = A->Diagonals[1]; - a_w1 = A->Diagonals[2]; - a_w = A->Diagonals[3]; - a_w_1 = A->Diagonals[4]; - } -} - -EdgePreserveLab::~EdgePreserveLab(){ - delete A; -} - -float *EdgePreserveLab::CreateBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, float *Blur, bool UseBlurForEdgeStop){ - if(Blur == NULL) - UseBlurForEdgeStop = false, //Use source if there's no supplied Blur. - Blur = new float[3*n]; - if(LScale == 0.0f){ - memcpy(Blur, Source, 3*n*sizeof(float)); - return Blur; - } - - //Create the edge stopping function a, rotationally symmetric and just one instead of (ax, ay). Maybe don't need Blur yet, so use its memory. - float *a, *b, *g; - if(UseBlurForEdgeStop) a = new float[n], g = Blur; - else a = Blur, g = Source; - //b = new float[n]; - - unsigned int x, y, i; - unsigned int w1 = w - 1, h1 = h - 1; - float eps = 0.0001f; - float scL = powf(100.0f,LScale); - float scab = powf(200.0f,abScale); - - float * var = new float[w*h]; - rtengine::boxvar(g, var, 1, 1, w, h); - -#ifdef _OPENMP -#pragma omp parallel for -#endif - for(y = 0; y < h1; y++){ - float *rg = &g[w*y]; - for(x = 0; x < w1; x++){ - //Estimate the central difference gradient in the center of a four pixel square. (gx, gy) is actually 2*gradient. - /*float gx = (fabs((rg[x + 1] - rg[x]) + (rg[x + w + 1] - rg[x + w]))); - float gy = (fabs((rg[x + w] - rg[x]) + (rg[x + w + 1] - rg[x + 1]))); - - //TODO: combine this with gx, gy if not needing separate quantities - float hx = (fabs((rg[x + 1 + n] - rg[x + n]) + (rg[x + w + 1 + n] - rg[x + w + n])) + \ - fabs((rg[x + 1 + 2*n] - rg[x + 2*n]) + (rg[x + w + 1 + 2*n] - rg[x + w + 2*n]))); - float hy = (fabs((rg[x + w + n] - rg[x + n]) + (rg[x + w + 1 + n] - rg[x + 1 + n])) + \ - fabs((rg[x + w + 2*n] - rg[x + 2*n]) + (rg[x + w + 1 + 2*n] - rg[x + 1 + 2*n]))); - */ - //float gradtot = (gx+gy+hx+hy); - //gradhisto[MAX(0,MIN(32767,(int)gradtot))] ++; - - //Apply power to the magnitude of the gradient to get the edge stopping function. - //a[x + w*y] = scL*expf(-100.0f*(gx + gy + hx + hy)/(EdgeStoppingLuma)); - //a[x + w*y] = scL*expf(-var[y*w+x]/SQR(0.02*EdgeStoppingLuma));///(0.1+rg[x]); - a[x + w*y] = scL*expf(-50.0f*sqrt(var[y*w+x])/(EdgeStoppingLuma+eps));///(0.1+rg[x]); - - //b[x + w*y] = (scab)*expf(-20.0f*(gx + gy + Lave*(hx + hy))/(EdgeStoppingChroma)); - //b[x + w*y] = (scab)*expf(-400.0f*SQR(gx + gy + Lave*(hx + hy))/SQR(EdgeStoppingChroma));; - - } - } - - /* Now setup the linear problem. I use the Maxima CAS, here's code for making an FEM formulation for the smoothness term: - p(x, y) := (1 - x)*(1 - y); - P(m, n) := A[m][n]*p(x, y) + A[m + 1][n]*p(1 - x, y) + A[m + 1][n + 1]*p(1 - x, 1 - y) + A[m][n + 1]*p(x, 1 - y); - Integrate(f) := integrate(integrate(f, x, 0, 1), y, 0, 1); - - Integrate(diff(P(u, v), x)*diff(p(x, y), x) + diff(P(u, v), y)*diff(p(x, y), y)); - Integrate(diff(P(u - 1, v), x)*diff(p(1 - x, y), x) + diff(P(u - 1, v), y)*diff(p(1 - x, y), y)); - Integrate(diff(P(u - 1, v - 1), x)*diff(p(1 - x, 1 - y), x) + diff(P(u - 1, v - 1), y)*diff(p(1 - x, 1 - y), y)); - Integrate(diff(P(u, v - 1), x)*diff(p(x, 1 - y), x) + diff(P(u, v - 1), y)*diff(p(x, 1 - y), y)); - So yeah. Use the numeric results of that to fill the matrix A.*/ - memset(a_1, 0, A->DiagonalLength(1)*sizeof(float)); - memset(a_w1, 0, A->DiagonalLength(w - 1)*sizeof(float)); - memset(a_w, 0, A->DiagonalLength(w)*sizeof(float)); - memset(a_w_1, 0, A->DiagonalLength(w + 1)*sizeof(float)); - -//TODO: OMP here? - for(i = y = 0; y != h; y++){ - for(x = 0; x != w; x++, i++){ - float ac; - a0[i] = 1.0; - - //Remember, only fill the lower triangle. Memory for upper is never made. It's symmetric. Trust. - if(x > 0 && y > 0) - ac = a[i - w - 1]/6.0f, - a_w_1[i - w - 1] -= 2.0f*ac, a_w[i - w] -= ac, - a_1[i - 1] -= ac, a0[i] += 4.0f*ac; - - if(x < w1 && y > 0) - ac = a[i - w]/6.0f, - a_w[i - w] -= ac, a_w1[i - w + 1] -= 2.0f*ac, - a0[i] += 4.0f*ac; - - if(x > 0 && y < h1) - ac = a[i - 1]/6.0f, - a_1[i - 1] -= ac, a0[i] += 4.0f*ac; - - if(x < w1 && y < h1) - a0[i] += 4.0f*a[i]/6.0f; - } - } - if(UseBlurForEdgeStop) delete[] a; - - - //Solve & return. - A->CreateIncompleteCholeskyFactorization(1); //Fill-in of 1 seems to work really good. More doesn't really help and less hurts (slightly). - if(!UseBlurForEdgeStop) memcpy(Blur, Source, 3*n*sizeof(float)); - // blur L channel - SparseConjugateGradient(A->PassThroughVectorProduct, Source, n, false, Blur, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve); - - //reset A for ab channels - /*memset(a_1, 0, A->DiagonalLength(1)*sizeof(float)); - memset(a_w1, 0, A->DiagonalLength(w - 1)*sizeof(float)); - memset(a_w, 0, A->DiagonalLength(w)*sizeof(float)); - memset(a_w_1, 0, A->DiagonalLength(w + 1)*sizeof(float)); - for(i = y = 0; y != h; y++){ - for(x = 0; x != w; x++, i++){ - float ac; - a0[i] = 1.0; - - //Remember, only fill the lower triangle. Memory for upper is never made. It's symmetric. Trust. - if(x > 0 && y > 0) - ac = b[i - w - 1]/6.0f, - a_w_1[i - w - 1] -= 2.0f*ac, a_w[i - w] -= ac, - a_1[i - 1] -= ac, a0[i] += 4.0f*ac; - - if(x < w1 && y > 0) - ac = b[i - w]/6.0f, - a_w[i - w] -= ac, a_w1[i - w + 1] -= 2.0f*ac, - a0[i] += 4.0f*ac; - - if(x > 0 && y < h1) - ac = b[i - 1]/6.0f, - a_1[i - 1] -= ac, a0[i] += 4.0f*ac; - - if(x < w1 && y < h1) - a0[i] += 4.0f*b[i]/6.0f; - } - }*/ - /*if(UseBlurForEdgeStop)*/ //delete[] b; - - // blur ab channels - //A->CreateIncompleteCholeskyFactorization(1); //Fill-in of 1 seems to work really good. More doesn't really help and less hurts (slightly). - //SparseConjugateGradient(A->PassThroughVectorProduct, Source+n, n, false, Blur+n, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve); - //SparseConjugateGradient(A->PassThroughVectorProduct, Source+2*n, n, false, Blur+2*n, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve); - - A->KillIncompleteCholeskyFactorization(); - return Blur; -} - -float *EdgePreserveLab::CreateIteratedBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, unsigned int Reweightings, float *Blur){ - //Simpler outcome? - if(Reweightings == 0) return CreateBlur(Source, LScale, abScale, EdgeStoppingLuma, EdgeStoppingChroma, Iterates, Blur); - - //Create a blur here, initialize. - if(Blur == NULL) Blur = new float[3*n]; - memcpy(Blur, Source, 3*n*sizeof(float)); - - //Iteratively improve the blur. - Reweightings++; - for(unsigned int i = 0; i != Reweightings; i++) - CreateBlur(Source, LScale, abScale, EdgeStoppingLuma, EdgeStoppingChroma, Iterates, Blur, true); - - return Blur; -} - -float *EdgePreserveLab::CompressDynamicRange(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, float CompressionExponent, float DetailBoost, unsigned int Iterates, unsigned int Reweightings, float *Compressed){ - //We're working with luminance, which does better logarithmic. - unsigned int i; - //for(i = 0; i != n; i++) - // Source[i] = logf(Source[i] + 0.0001f); - - //Blur. Also setup memory for Compressed (we can just use u since each element of u is used in one calculation). - float *u = CreateIteratedBlur(Source, LScale, abScale, EdgeStoppingLuma, EdgeStoppingChroma, Iterates, Reweightings); - if(Compressed == NULL) Compressed = u; - - //Apply compression, detail boost, unlogging. Compression is done on the logged data and detail boost on unlogged. - for(i = 0; i != n; i++){ - //float ce = expf(Source[i] + u[i]*(CompressionExponent - 1.0f)) - 0.0001f; - //float ue = expf(u[i]) - 0.0001f; - //Source[i] = expf(Source[i]) - 0.0001f; - //Compressed[i] = ce + DetailBoost*(Source[i] - ue); - Compressed[i] = u[i];//ue;//for testing, to display blur - } - - if(Compressed != u) delete[] u; - return Compressed; -} - - - - +#include "EdgePreserveLab.h" +#include "boxblur.h" +#include + +#ifdef _OPENMP +#include +#endif + +//#define MAX(a,b) ((a)<(b)?(b):(a)) +//#define MIN(a,b) ((a)>(b)?(b):(a)) + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +EdgePreserveLab::EdgePreserveLab(unsigned int width, unsigned int height){ + w = width; + h = height; + n = w*h; + + //Initialize the matrix just once at construction. + A = new MultiDiagonalSymmetricMatrix(n, 5); + if(!( + A->CreateDiagonal(0, 0) && + A->CreateDiagonal(1, 1) && + A->CreateDiagonal(2, w - 1) && + A->CreateDiagonal(3, w) && + A->CreateDiagonal(4, w + 1))){ + delete A; + A = NULL; + printf("Error in EdgePreserveLab construction: out of memory.\n"); + }else{ + a0 = A->Diagonals[0]; + a_1 = A->Diagonals[1]; + a_w1 = A->Diagonals[2]; + a_w = A->Diagonals[3]; + a_w_1 = A->Diagonals[4]; + } +} + +EdgePreserveLab::~EdgePreserveLab(){ + delete A; +} + +float *EdgePreserveLab::CreateBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, float *Blur, bool UseBlurForEdgeStop){ + if(Blur == NULL) + UseBlurForEdgeStop = false, //Use source if there's no supplied Blur. + Blur = new float[3*n]; + if(LScale == 0.0f){ + memcpy(Blur, Source, 3*n*sizeof(float)); + return Blur; + } + + //Create the edge stopping function a, rotationally symmetric and just one instead of (ax, ay). Maybe don't need Blur yet, so use its memory. + float *a, *b, *g; + if(UseBlurForEdgeStop) a = new float[n], g = Blur; + else a = Blur, g = Source; + //b = new float[n]; + + unsigned int x, y, i; + unsigned int w1 = w - 1, h1 = h - 1; + float eps = 0.0001f; + float scL = powf(100.0f,LScale); + float scab = powf(200.0f,abScale); + + float * var = new float[w*h]; + rtengine::boxvar(g, var, 1, 1, w, h); + +#ifdef _OPENMP +#pragma omp parallel for +#endif + for(y = 0; y < h1; y++){ + float *rg = &g[w*y]; + for(x = 0; x < w1; x++){ + //Estimate the central difference gradient in the center of a four pixel square. (gx, gy) is actually 2*gradient. + /*float gx = (fabs((rg[x + 1] - rg[x]) + (rg[x + w + 1] - rg[x + w]))); + float gy = (fabs((rg[x + w] - rg[x]) + (rg[x + w + 1] - rg[x + 1]))); + + //TODO: combine this with gx, gy if not needing separate quantities + float hx = (fabs((rg[x + 1 + n] - rg[x + n]) + (rg[x + w + 1 + n] - rg[x + w + n])) + \ + fabs((rg[x + 1 + 2*n] - rg[x + 2*n]) + (rg[x + w + 1 + 2*n] - rg[x + w + 2*n]))); + float hy = (fabs((rg[x + w + n] - rg[x + n]) + (rg[x + w + 1 + n] - rg[x + 1 + n])) + \ + fabs((rg[x + w + 2*n] - rg[x + 2*n]) + (rg[x + w + 1 + 2*n] - rg[x + 1 + 2*n]))); + */ + //float gradtot = (gx+gy+hx+hy); + //gradhisto[MAX(0,MIN(32767,(int)gradtot))] ++; + + //Apply power to the magnitude of the gradient to get the edge stopping function. + //a[x + w*y] = scL*expf(-100.0f*(gx + gy + hx + hy)/(EdgeStoppingLuma)); + //a[x + w*y] = scL*expf(-var[y*w+x]/SQR(0.02*EdgeStoppingLuma));///(0.1+rg[x]); + a[x + w*y] = scL*expf(-50.0f*sqrt(var[y*w+x])/(EdgeStoppingLuma+eps));///(0.1+rg[x]); + + //b[x + w*y] = (scab)*expf(-20.0f*(gx + gy + Lave*(hx + hy))/(EdgeStoppingChroma)); + //b[x + w*y] = (scab)*expf(-400.0f*SQR(gx + gy + Lave*(hx + hy))/SQR(EdgeStoppingChroma));; + + } + } + + /* Now setup the linear problem. I use the Maxima CAS, here's code for making an FEM formulation for the smoothness term: + p(x, y) := (1 - x)*(1 - y); + P(m, n) := A[m][n]*p(x, y) + A[m + 1][n]*p(1 - x, y) + A[m + 1][n + 1]*p(1 - x, 1 - y) + A[m][n + 1]*p(x, 1 - y); + Integrate(f) := integrate(integrate(f, x, 0, 1), y, 0, 1); + + Integrate(diff(P(u, v), x)*diff(p(x, y), x) + diff(P(u, v), y)*diff(p(x, y), y)); + Integrate(diff(P(u - 1, v), x)*diff(p(1 - x, y), x) + diff(P(u - 1, v), y)*diff(p(1 - x, y), y)); + Integrate(diff(P(u - 1, v - 1), x)*diff(p(1 - x, 1 - y), x) + diff(P(u - 1, v - 1), y)*diff(p(1 - x, 1 - y), y)); + Integrate(diff(P(u, v - 1), x)*diff(p(x, 1 - y), x) + diff(P(u, v - 1), y)*diff(p(x, 1 - y), y)); + So yeah. Use the numeric results of that to fill the matrix A.*/ + memset(a_1, 0, A->DiagonalLength(1)*sizeof(float)); + memset(a_w1, 0, A->DiagonalLength(w - 1)*sizeof(float)); + memset(a_w, 0, A->DiagonalLength(w)*sizeof(float)); + memset(a_w_1, 0, A->DiagonalLength(w + 1)*sizeof(float)); + +//TODO: OMP here? + for(i = y = 0; y != h; y++){ + for(x = 0; x != w; x++, i++){ + float ac; + a0[i] = 1.0; + + //Remember, only fill the lower triangle. Memory for upper is never made. It's symmetric. Trust. + if(x > 0 && y > 0) + ac = a[i - w - 1]/6.0f, + a_w_1[i - w - 1] -= 2.0f*ac, a_w[i - w] -= ac, + a_1[i - 1] -= ac, a0[i] += 4.0f*ac; + + if(x < w1 && y > 0) + ac = a[i - w]/6.0f, + a_w[i - w] -= ac, a_w1[i - w + 1] -= 2.0f*ac, + a0[i] += 4.0f*ac; + + if(x > 0 && y < h1) + ac = a[i - 1]/6.0f, + a_1[i - 1] -= ac, a0[i] += 4.0f*ac; + + if(x < w1 && y < h1) + a0[i] += 4.0f*a[i]/6.0f; + } + } + if(UseBlurForEdgeStop) delete[] a; + + + //Solve & return. + A->CreateIncompleteCholeskyFactorization(1); //Fill-in of 1 seems to work really good. More doesn't really help and less hurts (slightly). + if(!UseBlurForEdgeStop) memcpy(Blur, Source, 3*n*sizeof(float)); + // blur L channel + SparseConjugateGradient(A->PassThroughVectorProduct, Source, n, false, Blur, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve); + + //reset A for ab channels + /*memset(a_1, 0, A->DiagonalLength(1)*sizeof(float)); + memset(a_w1, 0, A->DiagonalLength(w - 1)*sizeof(float)); + memset(a_w, 0, A->DiagonalLength(w)*sizeof(float)); + memset(a_w_1, 0, A->DiagonalLength(w + 1)*sizeof(float)); + for(i = y = 0; y != h; y++){ + for(x = 0; x != w; x++, i++){ + float ac; + a0[i] = 1.0; + + //Remember, only fill the lower triangle. Memory for upper is never made. It's symmetric. Trust. + if(x > 0 && y > 0) + ac = b[i - w - 1]/6.0f, + a_w_1[i - w - 1] -= 2.0f*ac, a_w[i - w] -= ac, + a_1[i - 1] -= ac, a0[i] += 4.0f*ac; + + if(x < w1 && y > 0) + ac = b[i - w]/6.0f, + a_w[i - w] -= ac, a_w1[i - w + 1] -= 2.0f*ac, + a0[i] += 4.0f*ac; + + if(x > 0 && y < h1) + ac = b[i - 1]/6.0f, + a_1[i - 1] -= ac, a0[i] += 4.0f*ac; + + if(x < w1 && y < h1) + a0[i] += 4.0f*b[i]/6.0f; + } + }*/ + /*if(UseBlurForEdgeStop)*/ //delete[] b; + + // blur ab channels + //A->CreateIncompleteCholeskyFactorization(1); //Fill-in of 1 seems to work really good. More doesn't really help and less hurts (slightly). + //SparseConjugateGradient(A->PassThroughVectorProduct, Source+n, n, false, Blur+n, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve); + //SparseConjugateGradient(A->PassThroughVectorProduct, Source+2*n, n, false, Blur+2*n, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve); + + A->KillIncompleteCholeskyFactorization(); + return Blur; +} + +float *EdgePreserveLab::CreateIteratedBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, unsigned int Reweightings, float *Blur){ + //Simpler outcome? + if(Reweightings == 0) return CreateBlur(Source, LScale, abScale, EdgeStoppingLuma, EdgeStoppingChroma, Iterates, Blur); + + //Create a blur here, initialize. + if(Blur == NULL) Blur = new float[3*n]; + memcpy(Blur, Source, 3*n*sizeof(float)); + + //Iteratively improve the blur. + Reweightings++; + for(unsigned int i = 0; i != Reweightings; i++) + CreateBlur(Source, LScale, abScale, EdgeStoppingLuma, EdgeStoppingChroma, Iterates, Blur, true); + + return Blur; +} + +float *EdgePreserveLab::CompressDynamicRange(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, float CompressionExponent, float DetailBoost, unsigned int Iterates, unsigned int Reweightings, float *Compressed){ + //We're working with luminance, which does better logarithmic. + unsigned int i; + //for(i = 0; i != n; i++) + // Source[i] = logf(Source[i] + 0.0001f); + + //Blur. Also setup memory for Compressed (we can just use u since each element of u is used in one calculation). + float *u = CreateIteratedBlur(Source, LScale, abScale, EdgeStoppingLuma, EdgeStoppingChroma, Iterates, Reweightings); + if(Compressed == NULL) Compressed = u; + + //Apply compression, detail boost, unlogging. Compression is done on the logged data and detail boost on unlogged. + for(i = 0; i != n; i++){ + //float ce = expf(Source[i] + u[i]*(CompressionExponent - 1.0f)) - 0.0001f; + //float ue = expf(u[i]) - 0.0001f; + //Source[i] = expf(Source[i]) - 0.0001f; + //Compressed[i] = ce + DetailBoost*(Source[i] - ue); + Compressed[i] = u[i];//ue;//for testing, to display blur + } + + if(Compressed != u) delete[] u; + return Compressed; +} + + + + diff --git a/rtengine/EdgePreserveLab.h b/rtengine/EdgePreserveLab.h index 7da795247..70e97442c 100644 --- a/rtengine/EdgePreserveLab.h +++ b/rtengine/EdgePreserveLab.h @@ -1,76 +1,76 @@ -#pragma once -/* -The EdgePreserveLab files contain standard C++ (standard except the first line) code for creating and, to a -limited extent (create your own uses!), messing with multi scale edge preserving decompositions of a 32 bit single channel -image. As a byproduct it contains a lot of linear algebra which can be useful for optimization problems that -you want to solve in rectangles on rectangular grids. - -Anyway. Basically, this is an implementation of what's presented in the following papers: - Edge-Preserving Decompositions for Multi-Scale Tone and Detail Manipulation - An Iterative Solution Method for Linear Systems of Which the Coefficient Matrix is a Symetric M-Matrix - Color correction for tone mapping - Wikipedia, the free encyclopedia - -First one is most of what matters, next two are details, last everything else. I did a few things differently, especially: - Reformulated the minimization with finite elements instead of finite differences. This results in better conditioning, - slightly better accuracy (less artifacts), the possibility of a better picked edge stopping function, but more memory consumption. - - A single rotationally invariant edge stopping function is used instead of two non-invariant ones. - - Incomplete Cholseky factorization instead of Szeliski's LAHBF. Slower, but not subject to any patents. - - For tone mapping, original images are decomposed instead of their logarithms, and just one decomposition is made; - I find that this way works plenty good (theirs isn't better or worse... just different) and is simpler. - -Written by ben_pcc in Portland, Oregon, USA; code modified by Emil Martinec. - - // EdgePreserveLab.h and EdgePreserveLab.cpp are free software: - // you can redistribute it and/or modify it - // under the terms of the GNU General Public License as published by - // the Free Software Foundation, either version 3 of the License, or - // (at your option) any later version. - // - // This program is distributed in the hope that it will be useful, - // but WITHOUT ANY WARRANTY; without even the implied warranty of - // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - // GNU General Public License for more details. - // - // You should have received a copy of the GNU General Public License - // along with this program. If not, see . - -*/ - - - -#include -#include -#include -#include "EdgePreservingDecomposition.h" - -class EdgePreserveLab{ -public: - EdgePreserveLab(unsigned int width, unsigned int height); - ~EdgePreserveLab(); - - //Create an edge preserving blur of Source. Will create and return, or fill into Blur if not NULL. In place not ok. - //If UseBlurForEdgeStop is true, supplied not NULL Blur is used to calculate the edge stopping function instead of Source. - float *CreateBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, float *Blur = NULL, bool UseBlurForEdgeStop = false); - - //Iterates CreateBlur such that the smoothness term approaches a specific norm via iteratively reweighted least squares. In place not ok. - float *CreateIteratedBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, unsigned int Reweightings, float *Blur = NULL); - - /*Lowers global contrast while preserving or boosting local contrast. Can fill into Compressed. The smaller Compression - the more compression is applied, with Compression = 1 giving no effect and above 1 the opposite effect. You can totally - use Compression = 1 and play with DetailBoost for some really sweet unsharp masking. If working on luma/grey, consider giving it a logarithm. - In place calculation to save memory (Source == Compressed) is totally ok. Reweightings > 0 invokes CreateIteratedBlur instead of CreateBlur. */ - float *CompressDynamicRange(float *Source, float LScale = 1.0f, float abScale = 5.0f, float EdgeStoppingLuma = 1.0f, float EdgeStoppingChroma = 1.0f, - float CompressionExponent = 0.8f, float DetailBoost = 0.1f, unsigned int Iterates = 20, - unsigned int Reweightings = 0, float *Compressed = NULL); - -private: - MultiDiagonalSymmetricMatrix *A; //The equations are simple enough to not mandate a matrix class, but fast solution NEEDS a complicated preconditioner. - unsigned int w, h, n; - - //Convenient access to the data in A. - float *a0, *a_1, *a_w, *a_w_1, *a_w1; -}; +#pragma once +/* +The EdgePreserveLab files contain standard C++ (standard except the first line) code for creating and, to a +limited extent (create your own uses!), messing with multi scale edge preserving decompositions of a 32 bit single channel +image. As a byproduct it contains a lot of linear algebra which can be useful for optimization problems that +you want to solve in rectangles on rectangular grids. + +Anyway. Basically, this is an implementation of what's presented in the following papers: + Edge-Preserving Decompositions for Multi-Scale Tone and Detail Manipulation + An Iterative Solution Method for Linear Systems of Which the Coefficient Matrix is a Symetric M-Matrix + Color correction for tone mapping + Wikipedia, the free encyclopedia + +First one is most of what matters, next two are details, last everything else. I did a few things differently, especially: + Reformulated the minimization with finite elements instead of finite differences. This results in better conditioning, + slightly better accuracy (less artifacts), the possibility of a better picked edge stopping function, but more memory consumption. + + A single rotationally invariant edge stopping function is used instead of two non-invariant ones. + + Incomplete Cholseky factorization instead of Szeliski's LAHBF. Slower, but not subject to any patents. + + For tone mapping, original images are decomposed instead of their logarithms, and just one decomposition is made; + I find that this way works plenty good (theirs isn't better or worse... just different) and is simpler. + +Written by ben_pcc in Portland, Oregon, USA; code modified by Emil Martinec. + + // EdgePreserveLab.h and EdgePreserveLab.cpp are free software: + // you can redistribute it and/or modify it + // under the terms of the GNU General Public License as published by + // the Free Software Foundation, either version 3 of the License, or + // (at your option) any later version. + // + // This program is distributed in the hope that it will be useful, + // but WITHOUT ANY WARRANTY; without even the implied warranty of + // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + // GNU General Public License for more details. + // + // You should have received a copy of the GNU General Public License + // along with this program. If not, see . + +*/ + + + +#include +#include +#include +#include "EdgePreservingDecomposition.h" + +class EdgePreserveLab{ +public: + EdgePreserveLab(unsigned int width, unsigned int height); + ~EdgePreserveLab(); + + //Create an edge preserving blur of Source. Will create and return, or fill into Blur if not NULL. In place not ok. + //If UseBlurForEdgeStop is true, supplied not NULL Blur is used to calculate the edge stopping function instead of Source. + float *CreateBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, float *Blur = NULL, bool UseBlurForEdgeStop = false); + + //Iterates CreateBlur such that the smoothness term approaches a specific norm via iteratively reweighted least squares. In place not ok. + float *CreateIteratedBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, unsigned int Reweightings, float *Blur = NULL); + + /*Lowers global contrast while preserving or boosting local contrast. Can fill into Compressed. The smaller Compression + the more compression is applied, with Compression = 1 giving no effect and above 1 the opposite effect. You can totally + use Compression = 1 and play with DetailBoost for some really sweet unsharp masking. If working on luma/grey, consider giving it a logarithm. + In place calculation to save memory (Source == Compressed) is totally ok. Reweightings > 0 invokes CreateIteratedBlur instead of CreateBlur. */ + float *CompressDynamicRange(float *Source, float LScale = 1.0f, float abScale = 5.0f, float EdgeStoppingLuma = 1.0f, float EdgeStoppingChroma = 1.0f, + float CompressionExponent = 0.8f, float DetailBoost = 0.1f, unsigned int Iterates = 20, + unsigned int Reweightings = 0, float *Compressed = NULL); + +private: + MultiDiagonalSymmetricMatrix *A; //The equations are simple enough to not mandate a matrix class, but fast solution NEEDS a complicated preconditioner. + unsigned int w, h, n; + + //Convenient access to the data in A. + float *a0, *a_1, *a_w, *a_w_1, *a_w1; +}; diff --git a/rtengine/EdgePreservingDecomposition.cc b/rtengine/EdgePreservingDecomposition.cc index 6f8a30033..55022eb12 100644 --- a/rtengine/EdgePreservingDecomposition.cc +++ b/rtengine/EdgePreservingDecomposition.cc @@ -1,814 +1,814 @@ -#include -#include "rt_math.h" -#include "EdgePreservingDecomposition.h" -#ifdef _OPENMP -#include -#endif -#include "sleef.c" -#include "opthelper.h" - -#define pow_F(a,b) (xexpf(b*xlogf(a))) - -#define DIAGONALS 5 -#define DIAGONALSP1 6 - -/* Solves A x = b by the conjugate gradient method, where instead of feeding it the matrix A you feed it a function which -calculates A x where x is some vector. Stops when rms residual < RMSResidual or when maximum iterates is reached. -Stops at n iterates if MaximumIterates = 0 since that many iterates gives exact solution. Applicable to symmetric positive -definite problems only, which is what unconstrained smooth optimization pretty much always is. -Parameter pass can be passed through, containing whatever info you like it to contain (matrix info?). -Takes less memory with OkToModify_b = true, and Preconditioner = NULL. */ -float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), float *b, int n, bool OkToModify_b, - float *x, float RMSResidual, void *Pass, int MaximumIterates, void Preconditioner(float *Product, float *x, void *Pass)){ - int iterate, i; - - char* buffer = (char*)malloc(2*n*sizeof(float)+128); - float *r = (float*)(buffer+64); - //Start r and x. - if(x == NULL){ - x = new float[n]; - - memset(x, 0, sizeof(float)*n); //Zero initial guess if x == NULL. - memcpy(r, b, sizeof(float)*n); - }else{ - Ax(r, x, Pass); -#ifdef _OPENMP -#pragma omp parallel for // removed schedule(dynamic,10) -#endif - for(int ii = 0; ii < n; ii++) - r[ii] = b[ii] - r[ii]; //r = b - A x. - } - //s is preconditionment of r. Without, direct to r. - float *s = r, rs = 0.0f; - if(Preconditioner != NULL){ - s = new float[n]; - - Preconditioner(s, r, Pass); - } -#ifdef _OPENMP -#pragma omp parallel for reduction(+:rs) // removed schedule(dynamic,10) -#endif - for(int ii = 0; ii < n; ii++) { - rs += r[ii]*s[ii]; - } - //Search direction d. - float *d = (float*)(buffer + n*sizeof(float) + 128); - - memcpy(d, s, sizeof(float)*n); - - //Store calculations of Ax in this. - float *ax = b; - if(!OkToModify_b) ax = new float[n]; - - //Start iterating! - if(MaximumIterates == 0) MaximumIterates = n; - for(iterate = 0; iterate < MaximumIterates; iterate++){ - //Get step size alpha, store ax while at it. - float ab = 0.0f; - Ax(ax, d, Pass); -#ifdef _OPENMP -#pragma omp parallel for reduction(+:ab) -#endif - for(int ii = 0; ii < n; ii++) - ab += d[ii]*ax[ii]; - - if(ab == 0.0f) break; //So unlikely. It means perfectly converged or singular, stop either way. - ab = rs/ab; - - //Update x and r with this step size. - float rms = 0.0; -#ifdef _OPENMP -#pragma omp parallel for reduction(+:rms) -#endif - for(int ii = 0; ii < n; ii++){ - x[ii] += ab*d[ii]; - r[ii] -= ab*ax[ii]; //"Fast recursive formula", use explicit r = b - Ax occasionally? - rms += r[ii]*r[ii]; - } - rms = sqrtf(rms/n); - //Quit? This probably isn't the best stopping condition, but ok. - if(rms < RMSResidual) break; - - if(Preconditioner != NULL) Preconditioner(s, r, Pass); - - //Get beta. - ab = rs; - rs = 0.0f; - -#ifdef _OPENMP -#pragma omp parallel -#endif -{ - float c = 0.0f; - float t; - float temp; -#ifdef _OPENMP -#pragma omp for reduction(+:rs) // Summation with error correction -#endif - for(int ii = 0; ii < n; ii++) { - temp = r[ii]*s[ii]; - t = rs + temp; - if( fabsf(rs) >= fabsf(temp) ) - c += ((rs-t) + temp); - else - c += ((temp-t)+rs); - rs = t; - } -#ifdef _OPENMP -#pragma omp critical -#endif - rs += c; -} - - ab = rs/ab; - - //Update search direction p. -#ifdef _OPENMP -#pragma omp parallel for -#endif - for(int ii = 0; ii < n; ii++) - d[ii] = s[ii] + ab*d[ii]; - - - } - - if(iterate == MaximumIterates) - if(iterate != n && RMSResidual != 0.0f) - printf("Warning: MaximumIterates (%u) reached in SparseConjugateGradient.\n", MaximumIterates); - - if(ax != b) delete[] ax; - if(s != r) delete[] s; - free(buffer); - return x; -} - -MultiDiagonalSymmetricMatrix::MultiDiagonalSymmetricMatrix(int Dimension, int NumberOfDiagonalsInLowerTriangle){ - n = Dimension; - m = NumberOfDiagonalsInLowerTriangle; - IncompleteCholeskyFactorization = NULL; - - Diagonals = new float *[m]; - StartRows = new int [m+1]; - memset(Diagonals, 0, sizeof(float *)*m); - memset(StartRows, 0, sizeof(int)*(m+1)); - StartRows[m] = n+1; -} - -MultiDiagonalSymmetricMatrix::~MultiDiagonalSymmetricMatrix(){ - if(DiagBuffer != NULL) - free(buffer); - else - for(int i=0;i try to allocate smaller blocks - DiagBuffer = NULL; - else { - DiagBuffer = (char*)( ( uintptr_t(buffer) + uintptr_t(63)) / 64 * 64); - } - } - if(index >= m){ - printf("Error in MultiDiagonalSymmetricMatrix::CreateDiagonal: invalid index.\n"); - return false; - } - if(index > 0) - if(StartRow <= StartRows[index - 1]){ - printf("Error in MultiDiagonalSymmetricMatrix::CreateDiagonal: each StartRow must exceed the previous.\n"); - return false; - } - - if(DiagBuffer != NULL) - Diagonals[index] = (float*)(DiagBuffer+(index*(n+padding)*sizeof(float))+((index+16)*64)); - else { - Diagonals[index] = new float[DiagonalLength(StartRow)]; - if(Diagonals[index] == NULL) { - printf("Error in MultiDiagonalSymmetricMatrix::CreateDiagonal: memory allocation failed. Out of memory?\n"); - return false; - } - memset(Diagonals[index], 0, sizeof(float)*DiagonalLength(StartRow)); - } - - StartRows[index] = StartRow; - return true; -} - -inline int MultiDiagonalSymmetricMatrix::FindIndex(int StartRow) { - //There's GOT to be a better way to do this. "Bidirectional map?" - // Issue 1895 : Changed start of loop from zero to one - // m is small (5 or 6) - for(int i = 1; i < m; i++) - if(StartRows[i] == StartRow) - return i; - return -1; -} - -bool MultiDiagonalSymmetricMatrix::LazySetEntry(float value, int row, int column){ - //On the strict upper triangle? Swap, this is ok due to symmetry. - int i, sr; - if(column > row) - i = column, - column = row, - row = i; - if(row >= n) return false; - sr = row - column; - - //Locate the relevant diagonal. - i = FindIndex(sr); - if(i < 0) return false; - - Diagonals[i][column] = value; - return true; -} - -SSEFUNCTION void MultiDiagonalSymmetricMatrix::VectorProduct(float* RESTRICT Product, float* RESTRICT x){ - - int srm = StartRows[m-1]; - int lm = DiagonalLength(srm); -#ifdef _OPENMP -#ifdef __SSE2__ - const int chunkSize = (lm-srm)/(omp_get_num_procs()*32); -#else - const int chunkSize = (lm-srm)/(omp_get_num_procs()*8); -#endif -#endif -#pragma omp parallel -{ - // First fill the big part in the middle - // This can be done without intermediate stores to memory and it can be parallelized too -#ifdef _OPENMP -#pragma omp for schedule(dynamic,chunkSize) nowait -#endif -#ifdef __SSE2__ - for(int j=srm;j0;i--) { - int s = StartRows[i]; - prodv += (LVFU(Diagonals[i][j - s])*LVFU(x[j - s])) + (LVFU(Diagonals[i][j])*LVFU(x[j + s])); - } - _mm_storeu_ps(&Product[j],prodv); - } -#else - for(int j=srm;j0;i--) { - int s = StartRows[i]; - prod += (Diagonals[i][j - s]*x[j - s]) + (Diagonals[i][j]*x[j + s]); - } - Product[j] = prod; - } - -#endif -#pragma omp single -{ -#ifdef __SSE2__ - for(int j=lm-((lm-srm)%4);j0;i--) { - int s = StartRows[i]; - prod += (Diagonals[i][j - s]*x[j - s]) + (Diagonals[i][j]*x[j + s]); - } - Product[j] = prod; - } -#endif - // Fill remaining area - // Loop over the stored diagonals. - for(int i = 0; i < m; i++){ - int sr = StartRows[i]; - float *a = Diagonals[i]; //One fewer dereference. - int l = DiagonalLength(sr); - if(sr == 0) { - for(int j = 0; j < srm; j++) - Product[j] = a[j]*x[j]; //Separate, fairly simple treatment for the main diagonal. - for(int j = lm; j < l; j++) - Product[j] = a[j]*x[j]; //Separate, fairly simple treatment for the main diagonal. - } else { -// Split the loop in 3 parts, so now the big one in the middle can be parallelized without race conditions - // updates 0 to sr - 1. Because sr is small (in the range of image-width) no benefit by omp - for(int j=0;jCreateDiagonal(0, 0); //There's always a main diagonal in this type of decomposition. - mic=1; - for(int ii = 1; ii < m; ii++){ - //Set j to the number of diagonals to be created corresponding to a diagonal on this source matrix... - j = rtengine::min(StartRows[ii] - StartRows[ii - 1], MaxFillAbove); - - //...and create those diagonals. I want to take a moment to tell you about how much I love minimalistic loops: very much. - while(j-- != 0) - if(!ic->CreateDiagonal(mic++, StartRows[ii] - j)){ - //Beware of out of memory, possible for large, sparse problems if you ask for too much fill. - printf("Error in MultiDiagonalSymmetricMatrix::CreateIncompleteCholeskyFactorization: Out of memory. Ask for less fill?\n"); - delete ic; - return false; - } - } - - //It's all initialized? Uhkay. Do the actual math then. - int sss, ss, s; - int k, MaxStartRow = StartRows[m - 1]; //Handy number. - float **l = ic->Diagonals; - float *d = ic->Diagonals[0]; //Describes D in LDLt. - int icm = ic->m; - int icn = ic->n; - int* RESTRICT icStartRows = ic->StartRows; - - //Loop over the columns. - - // create array for quicker access to ic->StartRows - struct s_diagmap { - int sss; - int ss; - int k; - }; - - - // Pass one: count number of needed entries - int entrycount = 0; - for(int i=1;iFindIndex( icStartRows[i] + icStartRows[j]) > 0) - entrycount ++; - } - } - - // now we can create the array - struct s_diagmap* RESTRICT DiagMap = new s_diagmap[entrycount]; - // we also need the maxvalues - int entrynumber = 0; - int index; - int* RESTRICT MaxIndizes = new int[icm]; - - for(int i=1;iFindIndex( icStartRows[i] + icStartRows[j]); - if(index > 0) { - DiagMap[entrynumber].ss = j; - DiagMap[entrynumber].sss = index; - DiagMap[entrynumber].k = icStartRows[j]; - entrynumber ++; - } - } - MaxIndizes[i] = entrynumber - 1; - } - - int* RESTRICT findmap = new int[icm]; - for(int j=0;j= jMax) - break; //Possible values of j are limited - - float temp = 0.0f; - while(mapindex <= MaxIndizes[s] && ( k = DiagMap[mapindex].k) <= j) { - temp -= l[DiagMap[mapindex].sss][j - k]*l[DiagMap[mapindex].ss][j - k]*d[j - k]; - mapindex ++; - } - sss = findmap[s]; - l[s][j] = id * (sss < 0 ? temp : (Diagonals[sss][j] + temp)); - } - } - delete[] DiagMap; - delete[] MaxIndizes; - delete[] findmap; - IncompleteCholeskyFactorization = ic; - return true; -} - -void MultiDiagonalSymmetricMatrix::KillIncompleteCholeskyFactorization(void){ - delete IncompleteCholeskyFactorization; -} - -void MultiDiagonalSymmetricMatrix::CholeskyBackSolve(float* RESTRICT x, float* RESTRICT b){ - //We want to solve L D Lt x = b where D is a diagonal matrix described by Diagonals[0] and L is a unit lower triagular matrix described by the rest of the diagonals. - //Let D Lt x = y. Then, first solve L y = b. - float* RESTRICT *d = IncompleteCholeskyFactorization->Diagonals; - int* RESTRICT s = IncompleteCholeskyFactorization->StartRows; - int M = IncompleteCholeskyFactorization->m, N = IncompleteCholeskyFactorization->n; - int i, j; - - if(M != DIAGONALSP1){ // can happen in theory - for(j = 0; j < N; j++){ - float sub = b[j]; // using local var to reduce memory writes, gave a big speedup - i = 1; - int c = j - s[i]; - while(c >= 0) { - sub -= d[i][c]*x[c]; - i++; - c = j - s[i]; - } - x[j] = sub; // only one memory-write per j - } - } else { // that's the case almost every time - for(j = 0; j <= s[M-1]; j++){ - float sub = b[j]; // using local var to reduce memory writes, gave a big speedup - i = 1; - int c = j - s[1]; - while(c >= 0) { - sub -= d[i][c]*x[c]; - i++; - c = j - s[i]; - } - x[j] = sub; // only one memory-write per j - } - for(j = s[M-1]+1; j0;i--){ // using a constant upperbound allows the compiler to unroll this loop (gives a good speedup) - sub -= d[i][j-s[i]]*x[j-s[i]]; - } - x[j] = sub; // only one memory-write per j - } - } - - //Now, solve x from D Lt x = y -> Lt x = D^-1 y -// Took this one out of the while, so it can be parallelized now, which speeds up, because division is expensive -#ifdef _OPENMP -#pragma omp parallel for -#endif - for(j = 0; j < N; j++) - x[j] = x[j]/d[0][j]; - - if(M != DIAGONALSP1){ // can happen in theory - while(j-- > 0){ - float sub = x[j]; // using local var to reduce memory writes, gave a big speedup - i=1; - int c = j+s[1]; - while(c < N) { - sub -= d[i][j]*x[c]; - i++; - c = j+s[i]; - } - x[j] = sub; // only one memory-write per j - } - } else { // that's the case almost every time - for(j=N-1;j>=(N-1)-s[M-1];j--) { - float sub = x[j]; // using local var to reduce memory writes, gave a big speedup - i=1; - int c = j+s[1]; - while(c < N) { - sub -= d[i][j]*x[j+s[i]]; - i++; - c = j+s[i]; - } - x[j] = sub; // only one memory-write per j - } - for(j=(N-2)-s[M-1];j>=0;j--) { - float sub = x[j]; // using local var to reduce memory writes, gave a big speedup - for(int i=DIAGONALSP1-1;i>0;i--){ // using a constant upperbound allows the compiler to unroll this loop (gives a good speedup) - sub -= d[i][j]*x[j + s[i]]; - } - x[j] = sub; // only one memory-write per j - } - } -} - -EdgePreservingDecomposition::EdgePreservingDecomposition(int width, int height){ - w = width; - h = height; - n = w*h; - - //Initialize the matrix just once at construction. - A = new MultiDiagonalSymmetricMatrix(n, DIAGONALS); - if(!( - A->CreateDiagonal(0, 0) && - A->CreateDiagonal(1, 1) && - A->CreateDiagonal(2, w - 1) && - A->CreateDiagonal(3, w) && - A->CreateDiagonal(4, w + 1))){ - delete A; - A = NULL; - printf("Error in EdgePreservingDecomposition construction: out of memory.\n"); - }else{ - a0 = A->Diagonals[0]; - a_1 = A->Diagonals[1]; - a_w1 = A->Diagonals[2]; - a_w = A->Diagonals[3]; - a_w_1 = A->Diagonals[4]; - } -} - -EdgePreservingDecomposition::~EdgePreservingDecomposition(){ - delete A; -} - -SSEFUNCTION float *EdgePreservingDecomposition::CreateBlur(float *Source, float Scale, float EdgeStopping, int Iterates, float *Blur, bool UseBlurForEdgeStop){ - - if(Blur == NULL) - UseBlurForEdgeStop = false, //Use source if there's no supplied Blur. - Blur = new float[n]; - - if(Scale == 0.0f){ - memcpy(Blur, Source, n*sizeof(float)); - return Blur; - } - - //Create the edge stopping function a, rotationally symmetric and just one instead of (ax, ay). Maybe don't need Blur yet, so use its memory. - float* RESTRICT a; - float* RESTRICT g; - if(UseBlurForEdgeStop) a = new float[n], g = Blur; - else a = Blur, g = Source; - - int i; - int w1 = w - 1, h1 = h - 1; -// float eps = 0.02f; - const float sqreps = 0.0004f; // removed eps*eps from inner loop - - -#ifdef _OPENMP -#pragma omp parallel -#endif -{ -#ifdef __SSE2__ - int x; - __m128 gxv,gyv; - __m128 Scalev = _mm_set1_ps( Scale ); - __m128 sqrepsv = _mm_set1_ps( sqreps ); - __m128 EdgeStoppingv = _mm_set1_ps( -EdgeStopping ); - __m128 zd5v = _mm_set1_ps( 0.5f ); -#endif -#ifdef _OPENMP -#pragma omp for -#endif - for(int y = 0; y < h1; y++){ - float *rg = &g[w*y]; -#ifdef __SSE2__ - for(x = 0; x < w1-3; x+=4){ - //Estimate the central difference gradient in the center of a four pixel square. (gx, gy) is actually 2*gradient. - gxv = (LVFU(rg[x + 1]) - LVFU(rg[x])) + (LVFU(rg[x + w + 1]) - LVFU(rg[x + w])); - gyv = (LVFU(rg[x + w]) - LVFU(rg[x])) + (LVFU(rg[x + w + 1]) - LVFU(rg[x + 1])); - //Apply power to the magnitude of the gradient to get the edge stopping function. - _mm_storeu_ps( &a[x + w*y], Scalev * pow_F((zd5v*_mm_sqrt_ps(gxv*gxv + gyv*gyv + sqrepsv)), EdgeStoppingv) ); - } - for(; x < w1; x++){ - //Estimate the central difference gradient in the center of a four pixel square. (gx, gy) is actually 2*gradient. - float gx = (rg[x + 1] - rg[x]) + (rg[x + w + 1] - rg[x + w]); - float gy = (rg[x + w] - rg[x]) + (rg[x + w + 1] - rg[x + 1]); - //Apply power to the magnitude of the gradient to get the edge stopping function. - a[x + w*y] = Scale*pow_F(0.5f*sqrtf(gx*gx + gy*gy + sqreps), -EdgeStopping); - } -#else - for(int x = 0; x < w1; x++){ - //Estimate the central difference gradient in the center of a four pixel square. (gx, gy) is actually 2*gradient. - float gx = (rg[x + 1] - rg[x]) + (rg[x + w + 1] - rg[x + w]); - float gy = (rg[x + w] - rg[x]) + (rg[x + w + 1] - rg[x + 1]); - - //Apply power to the magnitude of the gradient to get the edge stopping function. - a[x + w*y] = Scale*pow_F(0.5f*sqrtf(gx*gx + gy*gy + sqreps), -EdgeStopping); - } -#endif - } -} - - - /* Now setup the linear problem. I use the Maxima CAS, here's code for making an FEM formulation for the smoothness term: - p(x, y) := (1 - x)*(1 - y); - P(m, n) := A[m][n]*p(x, y) + A[m + 1][n]*p(1 - x, y) + A[m + 1][n + 1]*p(1 - x, 1 - y) + A[m][n + 1]*p(x, 1 - y); - Integrate(f) := integrate(integrate(f, x, 0, 1), y, 0, 1); - - Integrate(diff(P(u, v), x)*diff(p(x, y), x) + diff(P(u, v), y)*diff(p(x, y), y)); - Integrate(diff(P(u - 1, v), x)*diff(p(1 - x, y), x) + diff(P(u - 1, v), y)*diff(p(1 - x, y), y)); - Integrate(diff(P(u - 1, v - 1), x)*diff(p(1 - x, 1 - y), x) + diff(P(u - 1, v - 1), y)*diff(p(1 - x, 1 - y), y)); - Integrate(diff(P(u, v - 1), x)*diff(p(x, 1 - y), x) + diff(P(u, v - 1), y)*diff(p(x, 1 - y), y)); - So yeah. Use the numeric results of that to fill the matrix A.*/ - - memset(a_1, 0, A->DiagonalLength(1)*sizeof(float)); - memset(a_w1, 0, A->DiagonalLength(w - 1)*sizeof(float)); - memset(a_w, 0, A->DiagonalLength(w)*sizeof(float)); - memset(a_w_1, 0, A->DiagonalLength(w + 1)*sizeof(float)); - - -// checked for race condition here -// a0[] is read and write but adressed by i only -// a[] is read only -// a_w_1 is write only -// a_w is write only -// a_w1 is write only -// a_1 is write only -// So, there should be no race conditions - -#ifdef _OPENMP -#pragma omp parallel for -#endif - for(int y = 0; y < h; y++){ - int i = y*w; - for(int x = 0; x < w; x++, i++){ - float ac,a0temp; - a0temp = 0.25f; - - //Remember, only fill the lower triangle. Memory for upper is never made. It's symmetric. Trust. - if(x > 0 && y > 0) { - ac = a[i - w - 1]/6.0f; - a_w_1[i - w - 1] -= 2.0f*ac; - a_w[i - w] -= ac; - a_1[i - 1] -= ac; - a0temp += ac; - } - if(x < w1 && y > 0) { - ac = a[i - w]/6.0f; - a_w[i - w] -= ac; - a_w1[i - w + 1] -= 2.0f*ac; - a0temp += ac; - } - if(x > 0 && y < h1) { - ac = a[i - 1]/6.0f; - a_1[i - 1] -= ac; - a0temp += ac; - } - if(x < w1 && y < h1) - a0temp += a[i]/6.0f; - a0[i] = 4.0f*a0temp; - } - } - - if(UseBlurForEdgeStop) delete[] a; - //Solve & return. - bool success=A->CreateIncompleteCholeskyFactorization(1); //Fill-in of 1 seems to work really good. More doesn't really help and less hurts (slightly). - if(!success) { - fprintf(stderr,"Error: Tonemapping has failed.\n"); - memset(Blur, 0, sizeof(float)*n); // On failure, set the blur to zero. This is subsequently exponentiated in CompressDynamicRange. - return Blur; - } - if(!UseBlurForEdgeStop) memcpy(Blur, Source, n*sizeof(float)); - SparseConjugateGradient(A->PassThroughVectorProduct, Source, n, false, Blur, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve); - A->KillIncompleteCholeskyFactorization(); - return Blur; -} - -float *EdgePreservingDecomposition::CreateIteratedBlur(float *Source, float Scale, float EdgeStopping, int Iterates, int Reweightings, float *Blur){ - //Simpler outcome? - if(Reweightings == 0) return CreateBlur(Source, Scale, EdgeStopping, Iterates, Blur); - - //Create a blur here, initialize. - if(Blur == NULL) Blur = new float[n]; - memcpy(Blur, Source, n*sizeof(float)); - - //Iteratively improve the blur. - Reweightings++; - for(int i = 0; i < Reweightings; i++) - CreateBlur(Source, Scale, EdgeStopping, Iterates, Blur, true); - - return Blur; -} - -SSEFUNCTION float *EdgePreservingDecomposition::CompressDynamicRange(float *Source, float Scale, float EdgeStopping, float CompressionExponent, float DetailBoost, int Iterates, int Reweightings, float *Compressed){ - if(w<300 && h<300) // set number of Reweightings to zero for small images (thumbnails). We could try to find a better solution here. - Reweightings = 0; - - //Small number intended to prevent division by zero. This is different from the eps in CreateBlur. - const float eps = 0.0001f; - - //We're working with luminance, which does better logarithmic. -#ifdef __SSE2__ -#ifdef _OPENMP -#pragma omp parallel -#endif -{ - __m128 epsv = _mm_set1_ps( eps ); -#ifdef _OPENMP -#pragma omp for -#endif - for(int ii = 0; ii < n-3; ii+=4) - _mm_storeu_ps( &Source[ii], xlogf(LVFU(Source[ii]) + epsv)); -} - for(int ii = n-(n%4); ii < n; ii++) - Source[ii] = xlogf(Source[ii] + eps); - -#else -#ifdef _OPENMP -#pragma omp parallel for -#endif - for(int ii = 0; ii < n; ii++) - Source[ii] = xlogf(Source[ii] + eps); -#endif - - //Blur. Also setup memory for Compressed (we can just use u since each element of u is used in one calculation). - float *u = CreateIteratedBlur(Source, Scale, EdgeStopping, Iterates, Reweightings); - if(Compressed == NULL) Compressed = u; - - //Apply compression, detail boost, unlogging. Compression is done on the logged data and detail boost on unlogged. -// float temp = CompressionExponent - 1.0f; - float temp; - if(DetailBoost>0.f) { - float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2) - temp = 1.2f*xlogf( -betemp); - } - else temp= CompressionExponent - 1.0f; -#ifdef __SSE2__ -#ifdef _OPENMP -#pragma omp parallel -#endif -{ - __m128 cev, uev, sourcev; - __m128 epsv = _mm_set1_ps( eps ); - __m128 DetailBoostv = _mm_set1_ps( DetailBoost ); - __m128 tempv = _mm_set1_ps( temp ); -#ifdef _OPENMP -#pragma omp for -#endif - for(int i = 0; i < n-3; i+=4){ - cev = xexpf(LVFU(Source[i]) + LVFU(u[i])*(tempv)) - epsv; - uev = xexpf(LVFU(u[i])) - epsv; - sourcev = xexpf(LVFU(Source[i])) - epsv; - _mm_storeu_ps( &Source[i], sourcev); - _mm_storeu_ps( &Compressed[i], cev + DetailBoostv * (sourcev - uev) ); - } -} - for(int i=n-(n%4); i < n; i++){ - float ce = xexpf(Source[i] + u[i]*(temp)) - eps; - float ue = xexpf(u[i]) - eps; - Source[i] = xexpf(Source[i]) - eps; - Compressed[i] = ce + DetailBoost*(Source[i] - ue); - } - -#else -#ifdef _OPENMP -#pragma omp parallel for -#endif - for(int i = 0; i < n; i++){ - float ce = xexpf(Source[i] + u[i]*(temp)) - eps; - float ue = xexpf(u[i]) - eps; - Source[i] = xexpf(Source[i]) - eps; - Compressed[i] = ce + DetailBoost*(Source[i] - ue); - } -#endif - - if(Compressed != u) delete[] u; - return Compressed; - -} - +#include +#include "rt_math.h" +#include "EdgePreservingDecomposition.h" +#ifdef _OPENMP +#include +#endif +#include "sleef.c" +#include "opthelper.h" + +#define pow_F(a,b) (xexpf(b*xlogf(a))) + +#define DIAGONALS 5 +#define DIAGONALSP1 6 + +/* Solves A x = b by the conjugate gradient method, where instead of feeding it the matrix A you feed it a function which +calculates A x where x is some vector. Stops when rms residual < RMSResidual or when maximum iterates is reached. +Stops at n iterates if MaximumIterates = 0 since that many iterates gives exact solution. Applicable to symmetric positive +definite problems only, which is what unconstrained smooth optimization pretty much always is. +Parameter pass can be passed through, containing whatever info you like it to contain (matrix info?). +Takes less memory with OkToModify_b = true, and Preconditioner = NULL. */ +float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), float *b, int n, bool OkToModify_b, + float *x, float RMSResidual, void *Pass, int MaximumIterates, void Preconditioner(float *Product, float *x, void *Pass)){ + int iterate, i; + + char* buffer = (char*)malloc(2*n*sizeof(float)+128); + float *r = (float*)(buffer+64); + //Start r and x. + if(x == NULL){ + x = new float[n]; + + memset(x, 0, sizeof(float)*n); //Zero initial guess if x == NULL. + memcpy(r, b, sizeof(float)*n); + }else{ + Ax(r, x, Pass); +#ifdef _OPENMP +#pragma omp parallel for // removed schedule(dynamic,10) +#endif + for(int ii = 0; ii < n; ii++) + r[ii] = b[ii] - r[ii]; //r = b - A x. + } + //s is preconditionment of r. Without, direct to r. + float *s = r, rs = 0.0f; + if(Preconditioner != NULL){ + s = new float[n]; + + Preconditioner(s, r, Pass); + } +#ifdef _OPENMP +#pragma omp parallel for reduction(+:rs) // removed schedule(dynamic,10) +#endif + for(int ii = 0; ii < n; ii++) { + rs += r[ii]*s[ii]; + } + //Search direction d. + float *d = (float*)(buffer + n*sizeof(float) + 128); + + memcpy(d, s, sizeof(float)*n); + + //Store calculations of Ax in this. + float *ax = b; + if(!OkToModify_b) ax = new float[n]; + + //Start iterating! + if(MaximumIterates == 0) MaximumIterates = n; + for(iterate = 0; iterate < MaximumIterates; iterate++){ + //Get step size alpha, store ax while at it. + float ab = 0.0f; + Ax(ax, d, Pass); +#ifdef _OPENMP +#pragma omp parallel for reduction(+:ab) +#endif + for(int ii = 0; ii < n; ii++) + ab += d[ii]*ax[ii]; + + if(ab == 0.0f) break; //So unlikely. It means perfectly converged or singular, stop either way. + ab = rs/ab; + + //Update x and r with this step size. + float rms = 0.0; +#ifdef _OPENMP +#pragma omp parallel for reduction(+:rms) +#endif + for(int ii = 0; ii < n; ii++){ + x[ii] += ab*d[ii]; + r[ii] -= ab*ax[ii]; //"Fast recursive formula", use explicit r = b - Ax occasionally? + rms += r[ii]*r[ii]; + } + rms = sqrtf(rms/n); + //Quit? This probably isn't the best stopping condition, but ok. + if(rms < RMSResidual) break; + + if(Preconditioner != NULL) Preconditioner(s, r, Pass); + + //Get beta. + ab = rs; + rs = 0.0f; + +#ifdef _OPENMP +#pragma omp parallel +#endif +{ + float c = 0.0f; + float t; + float temp; +#ifdef _OPENMP +#pragma omp for reduction(+:rs) // Summation with error correction +#endif + for(int ii = 0; ii < n; ii++) { + temp = r[ii]*s[ii]; + t = rs + temp; + if( fabsf(rs) >= fabsf(temp) ) + c += ((rs-t) + temp); + else + c += ((temp-t)+rs); + rs = t; + } +#ifdef _OPENMP +#pragma omp critical +#endif + rs += c; +} + + ab = rs/ab; + + //Update search direction p. +#ifdef _OPENMP +#pragma omp parallel for +#endif + for(int ii = 0; ii < n; ii++) + d[ii] = s[ii] + ab*d[ii]; + + + } + + if(iterate == MaximumIterates) + if(iterate != n && RMSResidual != 0.0f) + printf("Warning: MaximumIterates (%u) reached in SparseConjugateGradient.\n", MaximumIterates); + + if(ax != b) delete[] ax; + if(s != r) delete[] s; + free(buffer); + return x; +} + +MultiDiagonalSymmetricMatrix::MultiDiagonalSymmetricMatrix(int Dimension, int NumberOfDiagonalsInLowerTriangle){ + n = Dimension; + m = NumberOfDiagonalsInLowerTriangle; + IncompleteCholeskyFactorization = NULL; + + Diagonals = new float *[m]; + StartRows = new int [m+1]; + memset(Diagonals, 0, sizeof(float *)*m); + memset(StartRows, 0, sizeof(int)*(m+1)); + StartRows[m] = n+1; +} + +MultiDiagonalSymmetricMatrix::~MultiDiagonalSymmetricMatrix(){ + if(DiagBuffer != NULL) + free(buffer); + else + for(int i=0;i try to allocate smaller blocks + DiagBuffer = NULL; + else { + DiagBuffer = (char*)( ( uintptr_t(buffer) + uintptr_t(63)) / 64 * 64); + } + } + if(index >= m){ + printf("Error in MultiDiagonalSymmetricMatrix::CreateDiagonal: invalid index.\n"); + return false; + } + if(index > 0) + if(StartRow <= StartRows[index - 1]){ + printf("Error in MultiDiagonalSymmetricMatrix::CreateDiagonal: each StartRow must exceed the previous.\n"); + return false; + } + + if(DiagBuffer != NULL) + Diagonals[index] = (float*)(DiagBuffer+(index*(n+padding)*sizeof(float))+((index+16)*64)); + else { + Diagonals[index] = new float[DiagonalLength(StartRow)]; + if(Diagonals[index] == NULL) { + printf("Error in MultiDiagonalSymmetricMatrix::CreateDiagonal: memory allocation failed. Out of memory?\n"); + return false; + } + memset(Diagonals[index], 0, sizeof(float)*DiagonalLength(StartRow)); + } + + StartRows[index] = StartRow; + return true; +} + +inline int MultiDiagonalSymmetricMatrix::FindIndex(int StartRow) { + //There's GOT to be a better way to do this. "Bidirectional map?" + // Issue 1895 : Changed start of loop from zero to one + // m is small (5 or 6) + for(int i = 1; i < m; i++) + if(StartRows[i] == StartRow) + return i; + return -1; +} + +bool MultiDiagonalSymmetricMatrix::LazySetEntry(float value, int row, int column){ + //On the strict upper triangle? Swap, this is ok due to symmetry. + int i, sr; + if(column > row) + i = column, + column = row, + row = i; + if(row >= n) return false; + sr = row - column; + + //Locate the relevant diagonal. + i = FindIndex(sr); + if(i < 0) return false; + + Diagonals[i][column] = value; + return true; +} + +SSEFUNCTION void MultiDiagonalSymmetricMatrix::VectorProduct(float* RESTRICT Product, float* RESTRICT x){ + + int srm = StartRows[m-1]; + int lm = DiagonalLength(srm); +#ifdef _OPENMP +#ifdef __SSE2__ + const int chunkSize = (lm-srm)/(omp_get_num_procs()*32); +#else + const int chunkSize = (lm-srm)/(omp_get_num_procs()*8); +#endif +#endif +#pragma omp parallel +{ + // First fill the big part in the middle + // This can be done without intermediate stores to memory and it can be parallelized too +#ifdef _OPENMP +#pragma omp for schedule(dynamic,chunkSize) nowait +#endif +#ifdef __SSE2__ + for(int j=srm;j0;i--) { + int s = StartRows[i]; + prodv += (LVFU(Diagonals[i][j - s])*LVFU(x[j - s])) + (LVFU(Diagonals[i][j])*LVFU(x[j + s])); + } + _mm_storeu_ps(&Product[j],prodv); + } +#else + for(int j=srm;j0;i--) { + int s = StartRows[i]; + prod += (Diagonals[i][j - s]*x[j - s]) + (Diagonals[i][j]*x[j + s]); + } + Product[j] = prod; + } + +#endif +#pragma omp single +{ +#ifdef __SSE2__ + for(int j=lm-((lm-srm)%4);j0;i--) { + int s = StartRows[i]; + prod += (Diagonals[i][j - s]*x[j - s]) + (Diagonals[i][j]*x[j + s]); + } + Product[j] = prod; + } +#endif + // Fill remaining area + // Loop over the stored diagonals. + for(int i = 0; i < m; i++){ + int sr = StartRows[i]; + float *a = Diagonals[i]; //One fewer dereference. + int l = DiagonalLength(sr); + if(sr == 0) { + for(int j = 0; j < srm; j++) + Product[j] = a[j]*x[j]; //Separate, fairly simple treatment for the main diagonal. + for(int j = lm; j < l; j++) + Product[j] = a[j]*x[j]; //Separate, fairly simple treatment for the main diagonal. + } else { +// Split the loop in 3 parts, so now the big one in the middle can be parallelized without race conditions + // updates 0 to sr - 1. Because sr is small (in the range of image-width) no benefit by omp + for(int j=0;jCreateDiagonal(0, 0); //There's always a main diagonal in this type of decomposition. + mic=1; + for(int ii = 1; ii < m; ii++){ + //Set j to the number of diagonals to be created corresponding to a diagonal on this source matrix... + j = rtengine::min(StartRows[ii] - StartRows[ii - 1], MaxFillAbove); + + //...and create those diagonals. I want to take a moment to tell you about how much I love minimalistic loops: very much. + while(j-- != 0) + if(!ic->CreateDiagonal(mic++, StartRows[ii] - j)){ + //Beware of out of memory, possible for large, sparse problems if you ask for too much fill. + printf("Error in MultiDiagonalSymmetricMatrix::CreateIncompleteCholeskyFactorization: Out of memory. Ask for less fill?\n"); + delete ic; + return false; + } + } + + //It's all initialized? Uhkay. Do the actual math then. + int sss, ss, s; + int k, MaxStartRow = StartRows[m - 1]; //Handy number. + float **l = ic->Diagonals; + float *d = ic->Diagonals[0]; //Describes D in LDLt. + int icm = ic->m; + int icn = ic->n; + int* RESTRICT icStartRows = ic->StartRows; + + //Loop over the columns. + + // create array for quicker access to ic->StartRows + struct s_diagmap { + int sss; + int ss; + int k; + }; + + + // Pass one: count number of needed entries + int entrycount = 0; + for(int i=1;iFindIndex( icStartRows[i] + icStartRows[j]) > 0) + entrycount ++; + } + } + + // now we can create the array + struct s_diagmap* RESTRICT DiagMap = new s_diagmap[entrycount]; + // we also need the maxvalues + int entrynumber = 0; + int index; + int* RESTRICT MaxIndizes = new int[icm]; + + for(int i=1;iFindIndex( icStartRows[i] + icStartRows[j]); + if(index > 0) { + DiagMap[entrynumber].ss = j; + DiagMap[entrynumber].sss = index; + DiagMap[entrynumber].k = icStartRows[j]; + entrynumber ++; + } + } + MaxIndizes[i] = entrynumber - 1; + } + + int* RESTRICT findmap = new int[icm]; + for(int j=0;j= jMax) + break; //Possible values of j are limited + + float temp = 0.0f; + while(mapindex <= MaxIndizes[s] && ( k = DiagMap[mapindex].k) <= j) { + temp -= l[DiagMap[mapindex].sss][j - k]*l[DiagMap[mapindex].ss][j - k]*d[j - k]; + mapindex ++; + } + sss = findmap[s]; + l[s][j] = id * (sss < 0 ? temp : (Diagonals[sss][j] + temp)); + } + } + delete[] DiagMap; + delete[] MaxIndizes; + delete[] findmap; + IncompleteCholeskyFactorization = ic; + return true; +} + +void MultiDiagonalSymmetricMatrix::KillIncompleteCholeskyFactorization(void){ + delete IncompleteCholeskyFactorization; +} + +void MultiDiagonalSymmetricMatrix::CholeskyBackSolve(float* RESTRICT x, float* RESTRICT b){ + //We want to solve L D Lt x = b where D is a diagonal matrix described by Diagonals[0] and L is a unit lower triagular matrix described by the rest of the diagonals. + //Let D Lt x = y. Then, first solve L y = b. + float* RESTRICT *d = IncompleteCholeskyFactorization->Diagonals; + int* RESTRICT s = IncompleteCholeskyFactorization->StartRows; + int M = IncompleteCholeskyFactorization->m, N = IncompleteCholeskyFactorization->n; + int i, j; + + if(M != DIAGONALSP1){ // can happen in theory + for(j = 0; j < N; j++){ + float sub = b[j]; // using local var to reduce memory writes, gave a big speedup + i = 1; + int c = j - s[i]; + while(c >= 0) { + sub -= d[i][c]*x[c]; + i++; + c = j - s[i]; + } + x[j] = sub; // only one memory-write per j + } + } else { // that's the case almost every time + for(j = 0; j <= s[M-1]; j++){ + float sub = b[j]; // using local var to reduce memory writes, gave a big speedup + i = 1; + int c = j - s[1]; + while(c >= 0) { + sub -= d[i][c]*x[c]; + i++; + c = j - s[i]; + } + x[j] = sub; // only one memory-write per j + } + for(j = s[M-1]+1; j0;i--){ // using a constant upperbound allows the compiler to unroll this loop (gives a good speedup) + sub -= d[i][j-s[i]]*x[j-s[i]]; + } + x[j] = sub; // only one memory-write per j + } + } + + //Now, solve x from D Lt x = y -> Lt x = D^-1 y +// Took this one out of the while, so it can be parallelized now, which speeds up, because division is expensive +#ifdef _OPENMP +#pragma omp parallel for +#endif + for(j = 0; j < N; j++) + x[j] = x[j]/d[0][j]; + + if(M != DIAGONALSP1){ // can happen in theory + while(j-- > 0){ + float sub = x[j]; // using local var to reduce memory writes, gave a big speedup + i=1; + int c = j+s[1]; + while(c < N) { + sub -= d[i][j]*x[c]; + i++; + c = j+s[i]; + } + x[j] = sub; // only one memory-write per j + } + } else { // that's the case almost every time + for(j=N-1;j>=(N-1)-s[M-1];j--) { + float sub = x[j]; // using local var to reduce memory writes, gave a big speedup + i=1; + int c = j+s[1]; + while(c < N) { + sub -= d[i][j]*x[j+s[i]]; + i++; + c = j+s[i]; + } + x[j] = sub; // only one memory-write per j + } + for(j=(N-2)-s[M-1];j>=0;j--) { + float sub = x[j]; // using local var to reduce memory writes, gave a big speedup + for(int i=DIAGONALSP1-1;i>0;i--){ // using a constant upperbound allows the compiler to unroll this loop (gives a good speedup) + sub -= d[i][j]*x[j + s[i]]; + } + x[j] = sub; // only one memory-write per j + } + } +} + +EdgePreservingDecomposition::EdgePreservingDecomposition(int width, int height){ + w = width; + h = height; + n = w*h; + + //Initialize the matrix just once at construction. + A = new MultiDiagonalSymmetricMatrix(n, DIAGONALS); + if(!( + A->CreateDiagonal(0, 0) && + A->CreateDiagonal(1, 1) && + A->CreateDiagonal(2, w - 1) && + A->CreateDiagonal(3, w) && + A->CreateDiagonal(4, w + 1))){ + delete A; + A = NULL; + printf("Error in EdgePreservingDecomposition construction: out of memory.\n"); + }else{ + a0 = A->Diagonals[0]; + a_1 = A->Diagonals[1]; + a_w1 = A->Diagonals[2]; + a_w = A->Diagonals[3]; + a_w_1 = A->Diagonals[4]; + } +} + +EdgePreservingDecomposition::~EdgePreservingDecomposition(){ + delete A; +} + +SSEFUNCTION float *EdgePreservingDecomposition::CreateBlur(float *Source, float Scale, float EdgeStopping, int Iterates, float *Blur, bool UseBlurForEdgeStop){ + + if(Blur == NULL) + UseBlurForEdgeStop = false, //Use source if there's no supplied Blur. + Blur = new float[n]; + + if(Scale == 0.0f){ + memcpy(Blur, Source, n*sizeof(float)); + return Blur; + } + + //Create the edge stopping function a, rotationally symmetric and just one instead of (ax, ay). Maybe don't need Blur yet, so use its memory. + float* RESTRICT a; + float* RESTRICT g; + if(UseBlurForEdgeStop) a = new float[n], g = Blur; + else a = Blur, g = Source; + + int i; + int w1 = w - 1, h1 = h - 1; +// float eps = 0.02f; + const float sqreps = 0.0004f; // removed eps*eps from inner loop + + +#ifdef _OPENMP +#pragma omp parallel +#endif +{ +#ifdef __SSE2__ + int x; + __m128 gxv,gyv; + __m128 Scalev = _mm_set1_ps( Scale ); + __m128 sqrepsv = _mm_set1_ps( sqreps ); + __m128 EdgeStoppingv = _mm_set1_ps( -EdgeStopping ); + __m128 zd5v = _mm_set1_ps( 0.5f ); +#endif +#ifdef _OPENMP +#pragma omp for +#endif + for(int y = 0; y < h1; y++){ + float *rg = &g[w*y]; +#ifdef __SSE2__ + for(x = 0; x < w1-3; x+=4){ + //Estimate the central difference gradient in the center of a four pixel square. (gx, gy) is actually 2*gradient. + gxv = (LVFU(rg[x + 1]) - LVFU(rg[x])) + (LVFU(rg[x + w + 1]) - LVFU(rg[x + w])); + gyv = (LVFU(rg[x + w]) - LVFU(rg[x])) + (LVFU(rg[x + w + 1]) - LVFU(rg[x + 1])); + //Apply power to the magnitude of the gradient to get the edge stopping function. + _mm_storeu_ps( &a[x + w*y], Scalev * pow_F((zd5v*_mm_sqrt_ps(gxv*gxv + gyv*gyv + sqrepsv)), EdgeStoppingv) ); + } + for(; x < w1; x++){ + //Estimate the central difference gradient in the center of a four pixel square. (gx, gy) is actually 2*gradient. + float gx = (rg[x + 1] - rg[x]) + (rg[x + w + 1] - rg[x + w]); + float gy = (rg[x + w] - rg[x]) + (rg[x + w + 1] - rg[x + 1]); + //Apply power to the magnitude of the gradient to get the edge stopping function. + a[x + w*y] = Scale*pow_F(0.5f*sqrtf(gx*gx + gy*gy + sqreps), -EdgeStopping); + } +#else + for(int x = 0; x < w1; x++){ + //Estimate the central difference gradient in the center of a four pixel square. (gx, gy) is actually 2*gradient. + float gx = (rg[x + 1] - rg[x]) + (rg[x + w + 1] - rg[x + w]); + float gy = (rg[x + w] - rg[x]) + (rg[x + w + 1] - rg[x + 1]); + + //Apply power to the magnitude of the gradient to get the edge stopping function. + a[x + w*y] = Scale*pow_F(0.5f*sqrtf(gx*gx + gy*gy + sqreps), -EdgeStopping); + } +#endif + } +} + + + /* Now setup the linear problem. I use the Maxima CAS, here's code for making an FEM formulation for the smoothness term: + p(x, y) := (1 - x)*(1 - y); + P(m, n) := A[m][n]*p(x, y) + A[m + 1][n]*p(1 - x, y) + A[m + 1][n + 1]*p(1 - x, 1 - y) + A[m][n + 1]*p(x, 1 - y); + Integrate(f) := integrate(integrate(f, x, 0, 1), y, 0, 1); + + Integrate(diff(P(u, v), x)*diff(p(x, y), x) + diff(P(u, v), y)*diff(p(x, y), y)); + Integrate(diff(P(u - 1, v), x)*diff(p(1 - x, y), x) + diff(P(u - 1, v), y)*diff(p(1 - x, y), y)); + Integrate(diff(P(u - 1, v - 1), x)*diff(p(1 - x, 1 - y), x) + diff(P(u - 1, v - 1), y)*diff(p(1 - x, 1 - y), y)); + Integrate(diff(P(u, v - 1), x)*diff(p(x, 1 - y), x) + diff(P(u, v - 1), y)*diff(p(x, 1 - y), y)); + So yeah. Use the numeric results of that to fill the matrix A.*/ + + memset(a_1, 0, A->DiagonalLength(1)*sizeof(float)); + memset(a_w1, 0, A->DiagonalLength(w - 1)*sizeof(float)); + memset(a_w, 0, A->DiagonalLength(w)*sizeof(float)); + memset(a_w_1, 0, A->DiagonalLength(w + 1)*sizeof(float)); + + +// checked for race condition here +// a0[] is read and write but adressed by i only +// a[] is read only +// a_w_1 is write only +// a_w is write only +// a_w1 is write only +// a_1 is write only +// So, there should be no race conditions + +#ifdef _OPENMP +#pragma omp parallel for +#endif + for(int y = 0; y < h; y++){ + int i = y*w; + for(int x = 0; x < w; x++, i++){ + float ac,a0temp; + a0temp = 0.25f; + + //Remember, only fill the lower triangle. Memory for upper is never made. It's symmetric. Trust. + if(x > 0 && y > 0) { + ac = a[i - w - 1]/6.0f; + a_w_1[i - w - 1] -= 2.0f*ac; + a_w[i - w] -= ac; + a_1[i - 1] -= ac; + a0temp += ac; + } + if(x < w1 && y > 0) { + ac = a[i - w]/6.0f; + a_w[i - w] -= ac; + a_w1[i - w + 1] -= 2.0f*ac; + a0temp += ac; + } + if(x > 0 && y < h1) { + ac = a[i - 1]/6.0f; + a_1[i - 1] -= ac; + a0temp += ac; + } + if(x < w1 && y < h1) + a0temp += a[i]/6.0f; + a0[i] = 4.0f*a0temp; + } + } + + if(UseBlurForEdgeStop) delete[] a; + //Solve & return. + bool success=A->CreateIncompleteCholeskyFactorization(1); //Fill-in of 1 seems to work really good. More doesn't really help and less hurts (slightly). + if(!success) { + fprintf(stderr,"Error: Tonemapping has failed.\n"); + memset(Blur, 0, sizeof(float)*n); // On failure, set the blur to zero. This is subsequently exponentiated in CompressDynamicRange. + return Blur; + } + if(!UseBlurForEdgeStop) memcpy(Blur, Source, n*sizeof(float)); + SparseConjugateGradient(A->PassThroughVectorProduct, Source, n, false, Blur, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve); + A->KillIncompleteCholeskyFactorization(); + return Blur; +} + +float *EdgePreservingDecomposition::CreateIteratedBlur(float *Source, float Scale, float EdgeStopping, int Iterates, int Reweightings, float *Blur){ + //Simpler outcome? + if(Reweightings == 0) return CreateBlur(Source, Scale, EdgeStopping, Iterates, Blur); + + //Create a blur here, initialize. + if(Blur == NULL) Blur = new float[n]; + memcpy(Blur, Source, n*sizeof(float)); + + //Iteratively improve the blur. + Reweightings++; + for(int i = 0; i < Reweightings; i++) + CreateBlur(Source, Scale, EdgeStopping, Iterates, Blur, true); + + return Blur; +} + +SSEFUNCTION float *EdgePreservingDecomposition::CompressDynamicRange(float *Source, float Scale, float EdgeStopping, float CompressionExponent, float DetailBoost, int Iterates, int Reweightings, float *Compressed){ + if(w<300 && h<300) // set number of Reweightings to zero for small images (thumbnails). We could try to find a better solution here. + Reweightings = 0; + + //Small number intended to prevent division by zero. This is different from the eps in CreateBlur. + const float eps = 0.0001f; + + //We're working with luminance, which does better logarithmic. +#ifdef __SSE2__ +#ifdef _OPENMP +#pragma omp parallel +#endif +{ + __m128 epsv = _mm_set1_ps( eps ); +#ifdef _OPENMP +#pragma omp for +#endif + for(int ii = 0; ii < n-3; ii+=4) + _mm_storeu_ps( &Source[ii], xlogf(LVFU(Source[ii]) + epsv)); +} + for(int ii = n-(n%4); ii < n; ii++) + Source[ii] = xlogf(Source[ii] + eps); + +#else +#ifdef _OPENMP +#pragma omp parallel for +#endif + for(int ii = 0; ii < n; ii++) + Source[ii] = xlogf(Source[ii] + eps); +#endif + + //Blur. Also setup memory for Compressed (we can just use u since each element of u is used in one calculation). + float *u = CreateIteratedBlur(Source, Scale, EdgeStopping, Iterates, Reweightings); + if(Compressed == NULL) Compressed = u; + + //Apply compression, detail boost, unlogging. Compression is done on the logged data and detail boost on unlogged. +// float temp = CompressionExponent - 1.0f; + float temp; + if(DetailBoost>0.f) { + float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2) + temp = 1.2f*xlogf( -betemp); + } + else temp= CompressionExponent - 1.0f; +#ifdef __SSE2__ +#ifdef _OPENMP +#pragma omp parallel +#endif +{ + __m128 cev, uev, sourcev; + __m128 epsv = _mm_set1_ps( eps ); + __m128 DetailBoostv = _mm_set1_ps( DetailBoost ); + __m128 tempv = _mm_set1_ps( temp ); +#ifdef _OPENMP +#pragma omp for +#endif + for(int i = 0; i < n-3; i+=4){ + cev = xexpf(LVFU(Source[i]) + LVFU(u[i])*(tempv)) - epsv; + uev = xexpf(LVFU(u[i])) - epsv; + sourcev = xexpf(LVFU(Source[i])) - epsv; + _mm_storeu_ps( &Source[i], sourcev); + _mm_storeu_ps( &Compressed[i], cev + DetailBoostv * (sourcev - uev) ); + } +} + for(int i=n-(n%4); i < n; i++){ + float ce = xexpf(Source[i] + u[i]*(temp)) - eps; + float ue = xexpf(u[i]) - eps; + Source[i] = xexpf(Source[i]) - eps; + Compressed[i] = ce + DetailBoost*(Source[i] - ue); + } + +#else +#ifdef _OPENMP +#pragma omp parallel for +#endif + for(int i = 0; i < n; i++){ + float ce = xexpf(Source[i] + u[i]*(temp)) - eps; + float ue = xexpf(u[i]) - eps; + Source[i] = xexpf(Source[i]) - eps; + Compressed[i] = ce + DetailBoost*(Source[i] - ue); + } +#endif + + if(Compressed != u) delete[] u; + return Compressed; + +} + diff --git a/rtengine/EdgePreservingDecomposition.h b/rtengine/EdgePreservingDecomposition.h index 631ab7213..ff118408b 100644 --- a/rtengine/EdgePreservingDecomposition.h +++ b/rtengine/EdgePreservingDecomposition.h @@ -1,138 +1,138 @@ -#pragma once -/* -The EdgePreservingDecomposition files contain standard C++ (standard except the first line) code for creating and, to a -limited extent (create your own uses!), messing with multi scale edge preserving decompositions of a 32 bit single channel -image. As a byproduct it contains a lot of linear algebra which can be useful for optimization problems that -you want to solve in rectangles on rectangular grids. - -Anyway. Basically, this is an implementation of what's presented in the following papers: - Edge-Preserving Decompositions for Multi-Scale Tone and Detail Manipulation - An Iterative Solution Method for Linear Systems of Which the Coefficient Matrix is a Symetric M-Matrix - Color correction for tone mapping - Wikipedia, the free encyclopedia - -First one is most of what matters, next two are details, last everything else. I did a few things differently, especially: - Reformulated the minimization with finite elements instead of finite differences. This results in better conditioning, - slightly better accuracy (less artifacts), the possibility of a better picked edge stopping function, but more memory consumption. - - A single rotationally invariant edge stopping function is used instead of two non-invariant ones. - - Incomplete Cholseky factorization instead of Szeliski's LAHBF. Slower, but not subject to any patents. - - For tone mapping, original images are decomposed instead of their logarithms, and just one decomposition is made; - I find that this way works plenty good (theirs isn't better or worse... just different) and is simpler. - -Written by ben_pcc in Portland, Oregon, USA. Some history: - Late April 2010, I develop interest in this stuff because photos of my ceramics lack local contrast. - Mid 2010, it works but is too slow to be useful. - Fall 2010, various unsuccessful attempts at speeding up are tried. - Early December 2010, I get off the path of least resistance and write a matrix storage class with incomplete Cholesky decomposition. - 31 December 2010, the FEM reformulation works very well. - 1 January 2011, I'm cleaning up this file and readying it for initial release. - 12 - 14 November 2011, further cleanup, improvements, bug fixes, integration into Raw Therapee. - -It's likely that I'll take apart and rerelease contents of this file (in the distant future) as most of it isn't edge preserving decomposition -and rather supporting material. SparseConjugateGradient alone is a workhorse I and a few others have been exploiting for a few years. - -EdgePreservingDecomposition.h and EdgePreservingDecomposition.cpp are released under the following licence: - � It's free. - � You may not incorporate this code as part of proprietary or commercial software, but via freeware you may use its output for profit. - � You may modify and redistribute, but keep this big comment block intact and not for profit in any way unless I give specific permission. - � If you're unsure about anything else, treat as public domain. - � Don't be a dick. - -My email address is my screen name followed by @yahoo.com. I'm also known as ben_s or nonbasketless. Enjoy! -*/ - - - -#include -#include -#include -#include -#include "opthelper.h" - -//This is for solving big symmetric positive definite linear problems. -float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), float *b, int n, bool OkToModify_b = true, float *x = NULL, float RMSResidual = 0.0f, void *Pass = NULL, int MaximumIterates = 0, void Preconditioner(float *Product, float *x, void *Pass) = NULL); - -//Storage and use class for symmetric matrices, the nonzero contents of which are confined to diagonals. -class MultiDiagonalSymmetricMatrix{ -public: - MultiDiagonalSymmetricMatrix(int Dimension, int NumberOfDiagonalsInLowerTriangle); - ~MultiDiagonalSymmetricMatrix(); - - /* Storage of matrix data, and a function to create memory for Diagonals[index]. - Here's the storage scheme, designed to be simple both on paper and in C++: - - Let's say you have some diagonal. The StartRows is the row on which, at the left edge of the matrix, the diagonal "starts", - and StartRows must strictly increase with its index. The main diagonal for example has start row 0, its subdiagonal has 1, etc. - Then, Diagonal[j] is the matrix entry on the diagonal at column j. For efficiency, you're expected to learn this and fill in - public Diagonals manually. Symmetric matrices are represented by this class, and all symmetry is handled internally, you - only every worry or think about the lower trianglular (including main diagonal) part of the matrix. - */ +#pragma once +/* +The EdgePreservingDecomposition files contain standard C++ (standard except the first line) code for creating and, to a +limited extent (create your own uses!), messing with multi scale edge preserving decompositions of a 32 bit single channel +image. As a byproduct it contains a lot of linear algebra which can be useful for optimization problems that +you want to solve in rectangles on rectangular grids. + +Anyway. Basically, this is an implementation of what's presented in the following papers: + Edge-Preserving Decompositions for Multi-Scale Tone and Detail Manipulation + An Iterative Solution Method for Linear Systems of Which the Coefficient Matrix is a Symetric M-Matrix + Color correction for tone mapping + Wikipedia, the free encyclopedia + +First one is most of what matters, next two are details, last everything else. I did a few things differently, especially: + Reformulated the minimization with finite elements instead of finite differences. This results in better conditioning, + slightly better accuracy (less artifacts), the possibility of a better picked edge stopping function, but more memory consumption. + + A single rotationally invariant edge stopping function is used instead of two non-invariant ones. + + Incomplete Cholseky factorization instead of Szeliski's LAHBF. Slower, but not subject to any patents. + + For tone mapping, original images are decomposed instead of their logarithms, and just one decomposition is made; + I find that this way works plenty good (theirs isn't better or worse... just different) and is simpler. + +Written by ben_pcc in Portland, Oregon, USA. Some history: + Late April 2010, I develop interest in this stuff because photos of my ceramics lack local contrast. + Mid 2010, it works but is too slow to be useful. + Fall 2010, various unsuccessful attempts at speeding up are tried. + Early December 2010, I get off the path of least resistance and write a matrix storage class with incomplete Cholesky decomposition. + 31 December 2010, the FEM reformulation works very well. + 1 January 2011, I'm cleaning up this file and readying it for initial release. + 12 - 14 November 2011, further cleanup, improvements, bug fixes, integration into Raw Therapee. + +It's likely that I'll take apart and rerelease contents of this file (in the distant future) as most of it isn't edge preserving decomposition +and rather supporting material. SparseConjugateGradient alone is a workhorse I and a few others have been exploiting for a few years. + +EdgePreservingDecomposition.h and EdgePreservingDecomposition.cpp are released under the following licence: + � It's free. + � You may not incorporate this code as part of proprietary or commercial software, but via freeware you may use its output for profit. + � You may modify and redistribute, but keep this big comment block intact and not for profit in any way unless I give specific permission. + � If you're unsure about anything else, treat as public domain. + � Don't be a dick. + +My email address is my screen name followed by @yahoo.com. I'm also known as ben_s or nonbasketless. Enjoy! +*/ + + + +#include +#include +#include +#include +#include "opthelper.h" + +//This is for solving big symmetric positive definite linear problems. +float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), float *b, int n, bool OkToModify_b = true, float *x = NULL, float RMSResidual = 0.0f, void *Pass = NULL, int MaximumIterates = 0, void Preconditioner(float *Product, float *x, void *Pass) = NULL); + +//Storage and use class for symmetric matrices, the nonzero contents of which are confined to diagonals. +class MultiDiagonalSymmetricMatrix{ +public: + MultiDiagonalSymmetricMatrix(int Dimension, int NumberOfDiagonalsInLowerTriangle); + ~MultiDiagonalSymmetricMatrix(); + + /* Storage of matrix data, and a function to create memory for Diagonals[index]. + Here's the storage scheme, designed to be simple both on paper and in C++: + + Let's say you have some diagonal. The StartRows is the row on which, at the left edge of the matrix, the diagonal "starts", + and StartRows must strictly increase with its index. The main diagonal for example has start row 0, its subdiagonal has 1, etc. + Then, Diagonal[j] is the matrix entry on the diagonal at column j. For efficiency, you're expected to learn this and fill in + public Diagonals manually. Symmetric matrices are represented by this class, and all symmetry is handled internally, you + only every worry or think about the lower trianglular (including main diagonal) part of the matrix. + */ float **Diagonals; char *buffer; char *DiagBuffer; - int *StartRows; - bool CreateDiagonal(int index, int StartRow); - int n, m; //The matrix is n x n, with m diagonals on the lower triangle. Don't change these. They should be private but aren't for convenience. - inline int DiagonalLength(int StartRow){ //Gives number of elements in a diagonal. - return n - StartRow; - }; - - //Not efficient, but you can use it if you're lazy, or for early tests. Returns false if the row + column falls on no loaded diagonal, true otherwise. - bool LazySetEntry(float value, int row, int column); - - //Calculates the matrix-vector product of the matrix represented by this class onto the vector x. - void VectorProduct(float *Product, float *x); - - //Given the start row, attempts to find the corresponding index, or -1 if the StartRow doesn't exist. - inline int FindIndex(int StartRow) __attribute__((always_inline)); - - //This is the same as above, but designed to take this class as a pass through variable. By this way you can feed - //the meat of this class into an independent function, such as SparseConjugateGradient. - static void PassThroughVectorProduct(float *Product, float *x, void *Pass){ - (static_cast(Pass))->VectorProduct(Product, x); - }; - - /* CreateIncompleteCholeskyFactorization creates another matrix which is an incomplete (or complete if MaxFillAbove is big enough) - LDLt factorization of this matrix. Storage is like this: the first diagonal is the diagonal matrix D and the remaining diagonals - describe all of L except its main diagonal, which is a bunch of ones. Read up on the LDLt Cholesky factorization for what all this means. - Note that VectorProduct is nonsense. More useful to you is CholeskyBackSolve which fills x, where LDLt x = b. */ - bool CreateIncompleteCholeskyFactorization(int MaxFillAbove = 0); - void KillIncompleteCholeskyFactorization(void); - void CholeskyBackSolve(float *x, float *b); - MultiDiagonalSymmetricMatrix *IncompleteCholeskyFactorization; - - static void PassThroughCholeskyBackSolve(float *Product, float *x, void *Pass){ - (static_cast(Pass))->CholeskyBackSolve(Product, x); - }; - -}; - -class EdgePreservingDecomposition{ -public: - EdgePreservingDecomposition(int width, int height); - ~EdgePreservingDecomposition(); - - //Create an edge preserving blur of Source. Will create and return, or fill into Blur if not NULL. In place not ok. - //If UseBlurForEdgeStop is true, supplied not NULL Blur is used to calculate the edge stopping function instead of Source. - float *CreateBlur(float *Source, float Scale, float EdgeStopping, int Iterates, float *Blur = NULL, bool UseBlurForEdgeStop = false); - - //Iterates CreateBlur such that the smoothness term approaches a specific norm via iteratively reweighted least squares. In place not ok. - float *CreateIteratedBlur(float *Source, float Scale, float EdgeStopping, int Iterates, int Reweightings, float *Blur = NULL); - - /*Lowers global contrast while preserving or boosting local contrast. Can fill into Compressed. The smaller Compression - the more compression is applied, with Compression = 1 giving no effect and above 1 the opposite effect. You can totally - use Compression = 1 and play with DetailBoost for some really sweet unsharp masking. If working on luma/grey, consider giving it a logarithm. - In place calculation to save memory (Source == Compressed) is totally ok. Reweightings > 0 invokes CreateIteratedBlur instead of CreateBlur. */ - float *CompressDynamicRange(float *Source, float Scale = 1.0f, float EdgeStopping = 1.4f, float CompressionExponent = 0.8f, float DetailBoost = 0.1f, int Iterates = 20, int Reweightings = 0, float *Compressed = NULL); - -private: - MultiDiagonalSymmetricMatrix *A; //The equations are simple enough to not mandate a matrix class, but fast solution NEEDS a complicated preconditioner. - int w, h, n; - - //Convenient access to the data in A. - float * RESTRICT a0, * RESTRICT a_1, * RESTRICT a_w, * RESTRICT a_w_1, * RESTRICT a_w1; -}; - + int *StartRows; + bool CreateDiagonal(int index, int StartRow); + int n, m; //The matrix is n x n, with m diagonals on the lower triangle. Don't change these. They should be private but aren't for convenience. + inline int DiagonalLength(int StartRow){ //Gives number of elements in a diagonal. + return n - StartRow; + }; + + //Not efficient, but you can use it if you're lazy, or for early tests. Returns false if the row + column falls on no loaded diagonal, true otherwise. + bool LazySetEntry(float value, int row, int column); + + //Calculates the matrix-vector product of the matrix represented by this class onto the vector x. + void VectorProduct(float *Product, float *x); + + //Given the start row, attempts to find the corresponding index, or -1 if the StartRow doesn't exist. + inline int FindIndex(int StartRow) __attribute__((always_inline)); + + //This is the same as above, but designed to take this class as a pass through variable. By this way you can feed + //the meat of this class into an independent function, such as SparseConjugateGradient. + static void PassThroughVectorProduct(float *Product, float *x, void *Pass){ + (static_cast(Pass))->VectorProduct(Product, x); + }; + + /* CreateIncompleteCholeskyFactorization creates another matrix which is an incomplete (or complete if MaxFillAbove is big enough) + LDLt factorization of this matrix. Storage is like this: the first diagonal is the diagonal matrix D and the remaining diagonals + describe all of L except its main diagonal, which is a bunch of ones. Read up on the LDLt Cholesky factorization for what all this means. + Note that VectorProduct is nonsense. More useful to you is CholeskyBackSolve which fills x, where LDLt x = b. */ + bool CreateIncompleteCholeskyFactorization(int MaxFillAbove = 0); + void KillIncompleteCholeskyFactorization(void); + void CholeskyBackSolve(float *x, float *b); + MultiDiagonalSymmetricMatrix *IncompleteCholeskyFactorization; + + static void PassThroughCholeskyBackSolve(float *Product, float *x, void *Pass){ + (static_cast(Pass))->CholeskyBackSolve(Product, x); + }; + +}; + +class EdgePreservingDecomposition{ +public: + EdgePreservingDecomposition(int width, int height); + ~EdgePreservingDecomposition(); + + //Create an edge preserving blur of Source. Will create and return, or fill into Blur if not NULL. In place not ok. + //If UseBlurForEdgeStop is true, supplied not NULL Blur is used to calculate the edge stopping function instead of Source. + float *CreateBlur(float *Source, float Scale, float EdgeStopping, int Iterates, float *Blur = NULL, bool UseBlurForEdgeStop = false); + + //Iterates CreateBlur such that the smoothness term approaches a specific norm via iteratively reweighted least squares. In place not ok. + float *CreateIteratedBlur(float *Source, float Scale, float EdgeStopping, int Iterates, int Reweightings, float *Blur = NULL); + + /*Lowers global contrast while preserving or boosting local contrast. Can fill into Compressed. The smaller Compression + the more compression is applied, with Compression = 1 giving no effect and above 1 the opposite effect. You can totally + use Compression = 1 and play with DetailBoost for some really sweet unsharp masking. If working on luma/grey, consider giving it a logarithm. + In place calculation to save memory (Source == Compressed) is totally ok. Reweightings > 0 invokes CreateIteratedBlur instead of CreateBlur. */ + float *CompressDynamicRange(float *Source, float Scale = 1.0f, float EdgeStopping = 1.4f, float CompressionExponent = 0.8f, float DetailBoost = 0.1f, int Iterates = 20, int Reweightings = 0, float *Compressed = NULL); + +private: + MultiDiagonalSymmetricMatrix *A; //The equations are simple enough to not mandate a matrix class, but fast solution NEEDS a complicated preconditioner. + int w, h, n; + + //Convenient access to the data in A. + float * RESTRICT a0, * RESTRICT a_1, * RESTRICT a_w, * RESTRICT a_w_1, * RESTRICT a_w1; +}; + diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 6b3a808ac..d2d9249ea 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -1,2945 +1,2945 @@ -//////////////////////////////////////////////////////////////// -// -// CFA denoise by wavelet transform, FT filtering -// -// copyright (c) 2008-2012 Emil Martinec -// -// -// code dated: March 9, 2012 -// -// FTblockDN.cc is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -//////////////////////////////////////////////////////////////// - -#include -#include -#include "../rtgui/threadutils.h" -#include "rtengine.h" -#include "improcfun.h" -#include "LUT.h" -#include "array2D.h" -#include "iccmatrices.h" -#include "boxblur.h" -#include "rt_math.h" -#include "mytime.h" -#include "sleef.c" -#include "opthelper.h" -#include "cplx_wavelet_dec.h" - -#ifdef _OPENMP -#include -#endif - -#define TS 64 // Tile size -#define offset 25 // shift between tiles -#define fTS ((TS/2+1)) // second dimension of Fourier tiles -#define blkrad 1 // radius of block averaging - -#define epsilon 0.001f/(TS*TS) //tolerance - -#define med2(a0,a1,a2,a3,a4,median) { \ -pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; \ -PIX_SORT(pp[0],pp[1]) ; PIX_SORT(pp[3],pp[4]) ; PIX_SORT(pp[0],pp[3]) ;\ -PIX_SORT(pp[1],pp[4]) ; PIX_SORT(pp[1],pp[2]) ; PIX_SORT(pp[2],pp[3]) ;\ -PIX_SORT(pp[1],pp[2]) ; median=pp[2] ;} - -#define med5(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,median) { \ -pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; pp[5]=a5; pp[6]=a6; pp[7]=a7; pp[8]=a8; pp[9]=a9; pp[10]=a10; pp[11]=a11; pp[12]=a12; \ -pp[13]=a13; pp[14]=a14; pp[15]=a15; pp[16]=a16; pp[17]=a17; pp[18]=a18; pp[19]=a19; pp[20]=a20; pp[21]=a21; pp[22]=a22; pp[23]=a23; pp[24]=a24; \ -PIX_SORT(pp[0], pp[1]) ; PIX_SORT(pp[3], pp[4]) ; PIX_SORT(pp[2], pp[4]) ;\ -PIX_SORT(pp[2], pp[3]) ; PIX_SORT(pp[6], pp[7]) ; PIX_SORT(pp[5], pp[7]) ;\ -PIX_SORT(pp[5], pp[6]) ; PIX_SORT(pp[9], pp[10]) ; PIX_SORT(pp[8], pp[10]) ;\ -PIX_SORT(pp[8], pp[9]) ; PIX_SORT(pp[12], pp[13]) ; PIX_SORT(pp[11], pp[13]) ;\ -PIX_SORT(pp[11], pp[12]) ; PIX_SORT(pp[15], pp[16]) ; PIX_SORT(pp[14], pp[16]) ;\ -PIX_SORT(pp[14], pp[15]) ; PIX_SORT(pp[18], pp[19]) ; PIX_SORT(pp[17], pp[19]) ;\ -PIX_SORT(pp[17], pp[18]) ; PIX_SORT(pp[21], pp[22]) ; PIX_SORT(pp[20], pp[22]) ;\ -PIX_SORT(pp[20], pp[21]) ; PIX_SORT(pp[23], pp[24]) ; PIX_SORT(pp[2], pp[5]) ;\ -PIX_SORT(pp[3], pp[6]) ; PIX_SORT(pp[0], pp[6]) ; PIX_SORT(pp[0], pp[3]) ;\ -PIX_SORT(pp[4], pp[7]) ; PIX_SORT(pp[1], pp[7]) ; PIX_SORT(pp[1], pp[4]) ;\ -PIX_SORT(pp[11], pp[14]) ; PIX_SORT(pp[8], pp[14]) ; PIX_SORT(pp[8], pp[11]) ;\ -PIX_SORT(pp[12], pp[15]) ; PIX_SORT(pp[9], pp[15]) ; PIX_SORT(pp[9], pp[12]) ;\ -PIX_SORT(pp[13], pp[16]) ; PIX_SORT(pp[10], pp[16]) ; PIX_SORT(pp[10], pp[13]) ;\ -PIX_SORT(pp[20], pp[23]) ; PIX_SORT(pp[17], pp[23]) ; PIX_SORT(pp[17], pp[20]) ;\ -PIX_SORT(pp[21], pp[24]) ; PIX_SORT(pp[18], pp[24]) ; PIX_SORT(pp[18], pp[21]) ;\ -PIX_SORT(pp[19], pp[22]) ; PIX_SORT(pp[8], pp[17]) ; PIX_SORT(pp[9], pp[18]) ;\ -PIX_SORT(pp[0], pp[18]) ; PIX_SORT(pp[0], pp[9]) ; PIX_SORT(pp[10], pp[19]) ;\ -PIX_SORT(pp[1], pp[19]) ; PIX_SORT(pp[1], pp[10]) ; PIX_SORT(pp[11], pp[20]) ;\ -PIX_SORT(pp[2], pp[20]) ; PIX_SORT(pp[2], pp[11]) ; PIX_SORT(pp[12], pp[21]) ;\ -PIX_SORT(pp[3], pp[21]) ; PIX_SORT(pp[3], pp[12]) ; PIX_SORT(pp[13], pp[22]) ;\ -PIX_SORT(pp[4], pp[22]) ; PIX_SORT(pp[4], pp[13]) ; PIX_SORT(pp[14], pp[23]) ;\ -PIX_SORT(pp[5], pp[23]) ; PIX_SORT(pp[5], pp[14]) ; PIX_SORT(pp[15], pp[24]) ;\ -PIX_SORT(pp[6], pp[24]) ; PIX_SORT(pp[6], pp[15]) ; PIX_SORT(pp[7], pp[16]) ;\ -PIX_SORT(pp[7], pp[19]) ; PIX_SORT(pp[13], pp[21]) ; PIX_SORT(pp[15], pp[23]) ;\ -PIX_SORT(pp[7], pp[13]) ; PIX_SORT(pp[7], pp[15]) ; PIX_SORT(pp[1], pp[9]) ;\ -PIX_SORT(pp[3], pp[11]) ; PIX_SORT(pp[5], pp[17]) ; PIX_SORT(pp[11], pp[17]) ;\ -PIX_SORT(pp[9], pp[17]) ; PIX_SORT(pp[4], pp[10]) ; PIX_SORT(pp[6], pp[12]) ;\ -PIX_SORT(pp[7], pp[14]) ; PIX_SORT(pp[4], pp[6]) ; PIX_SORT(pp[4], pp[7]) ;\ -PIX_SORT(pp[12], pp[14]) ; PIX_SORT(pp[10], pp[14]) ; PIX_SORT(pp[6], pp[7]) ;\ -PIX_SORT(pp[10], pp[12]) ; PIX_SORT(pp[6], pp[10]) ; PIX_SORT(pp[6], pp[17]) ;\ -PIX_SORT(pp[12], pp[17]) ; PIX_SORT(pp[7], pp[17]) ; PIX_SORT(pp[7], pp[10]) ;\ -PIX_SORT(pp[12], pp[18]) ; PIX_SORT(pp[7], pp[12]) ; PIX_SORT(pp[10], pp[18]) ;\ -PIX_SORT(pp[12], pp[20]) ; PIX_SORT(pp[10], pp[20]) ; PIX_SORT(pp[10], pp[12]) ;\ -median=pp[12];} - -#define ELEM_FLOAT_SWAP(a,b) { register float t=(a);(a)=(b);(b)=t; } - -namespace rtengine { - - // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - /* - Structure of the algorithm: - - 1. Compute an initial denoise of the image via undecimated wavelet transform - and universal thresholding modulated by user input. - 2. Decompose the residual image into TSxTS size tiles, shifting by 'offset' each step - (so roughly each pixel is in (TS/offset)^2 tiles); Discrete Cosine transform the tiles. - 3. Filter the DCT data to pick out patterns missed by the wavelet denoise - 4. Inverse DCT the denoised tile data and combine the tiles into a denoised output image. - - */ - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -extern const Settings* settings; - -// Median calculation using quicksort -float fq_sort2(float arr[], int n) -{ - int low = 0; - int high = n-1; - int median = (low + high) / 2; - - for (;;) { - if (high <= low) - return arr[median] ; - if (high == low + 1) { - if (arr[low] > arr[high]) - ELEM_FLOAT_SWAP(arr[low], arr[high]) ; - return arr[median] ; - } - - int middle = (low + high) / 2; - if (arr[middle] > arr[high]) ELEM_FLOAT_SWAP(arr[middle], arr[high]) ; - if (arr[low] > arr[high]) ELEM_FLOAT_SWAP(arr[low], arr[high]) ; - if (arr[middle] > arr[low]) ELEM_FLOAT_SWAP(arr[middle], arr[low]) ; - - ELEM_FLOAT_SWAP(arr[middle], arr[low+1]) ; - int ll = low + 1; - int hh = high; - - for (;;) { - do ll++; while (arr[low] > arr[ll]) ; - do hh--; while (arr[hh] > arr[low]) ; - - if (hh < ll) - break; - - ELEM_FLOAT_SWAP(arr[ll], arr[hh]) ; - } - - ELEM_FLOAT_SWAP(arr[low], arr[hh]) ; - - if (hh <= median) - low = ll; - if (hh >= median) - high = hh - 1; - } - } - -float media(float *elements, int N) -{ - - // Order elements (only half of them) - for (int i = 0; i < (N >> 1) + 1; ++i) - { - // Find position of minimum element - int min = i; - for (int j = i + 1; j < N; ++j) - if (elements[j] < elements[min]) - min = j; - // Put found minimum element in its place - float temp = elements[i]; - elements[i] = elements[min]; - elements[min] = temp; - } - // Get result - the middle element - return elements[N >> 1]; -} - -void ImProcFunctions::Median_Denoise( float **src, float **dst, const int width, const int height, const mediantype medianType, const int iterations, const int numThreads, float **buffer) -{ - int border=1, numElements, middleElement; - switch(medianType) { - case MED_3X3SOFT: - case MED_3X3STRONG: - border = 1; - break; - case MED_5X5SOFT: - border = 2; - break; - case MED_5X5STRONG: - border = 2; - break; - case MED_7X7: - border = 3; - numElements = 49; - middleElement = 24; - break; - default: // includes MED_9X9 - border = 4; - numElements = 81; - middleElement = 40; - } - - float **allocBuffer = NULL; - float **medBuffer[2]; - medBuffer[0] = src; - // we need a buffer if src == dst or if (src != dst && iterations > 1) - if(src == dst || (src != dst && iterations>1)) { - if(buffer == NULL) { // we didn't get a buufer => create one - allocBuffer = new float*[height]; - for (int i=0; i use it - medBuffer[1] = buffer; - } - } else { // we can write directly into destination - medBuffer[1] = dst; - } - - float ** medianIn, ** medianOut; - int BufferIndex = 0; - for(int iteration=1;iteration<=iterations;iteration++){ - medianIn = medBuffer[BufferIndex]; - medianOut = medBuffer[BufferIndex^1]; - - if(iteration == 1) { // upper border - for (int i=0; i1) -#endif - for (int i=border; i1) -#endif - for(int i = border; i < height-border; i++ ) { - for(int j = border; j < width-border; j++) { - dst[i][j] = medianOut[i][j]; - } - } - } - if(allocBuffer != NULL) { // we allocated memory, so let's free it now - for (int i=0; icopyData(dst); - if(calclum) { - delete calclum; - calclum = NULL; - } - - return; - } - - static MyMutex FftwMutex; - MyMutex::MyLock lock(FftwMutex); - - const nrquality nrQuality = (dnparams.smethod == "shal") ? QUALITY_STANDARD : QUALITY_HIGH;//shrink method - const float qhighFactor = (nrQuality == QUALITY_HIGH) ? 1.f/(float) settings->nrhigh : 1.0f; - const bool useNoiseCCurve = (noiseCCurve && noiseCCurve.getSum() > 5.f ); - const bool useNoiseLCurve = (noiseLCurve && noiseLCurve.getSum() >= 7.f ); - const bool autoch = (settings->leveldnautsimpl==1 && (dnparams.Cmethod=="AUT" || dnparams.Cmethod=="PRE")) || (settings->leveldnautsimpl==0 && (dnparams.C2method=="AUTO" || dnparams.C2method=="PREV")); - - float** lumcalc; - float* lumcalcBuffer; - float** ccalc; - float* ccalcBuffer; - - bool ponder=false; - float ponderCC=1.f; - if(settings->leveldnautsimpl==1 && params->dirpyrDenoise.Cmethod=="PON") {ponder=true;ponderCC=0.5f;} - if(settings->leveldnautsimpl==1 && params->dirpyrDenoise.Cmethod=="PRE") {ponderCC=0.5f;} - if(settings->leveldnautsimpl==0 && params->dirpyrDenoise.Cmethod=="PREV") {ponderCC=0.5f;} - - int metchoice=0; - if(dnparams.methodmed=="Lonly") metchoice=1; - else if(dnparams.methodmed=="Lab") metchoice=2; - else if(dnparams.methodmed=="ab") metchoice=3; - else if(dnparams.methodmed=="Lpab") metchoice=4; - - const bool denoiseMethodRgb = (dnparams.dmethod == "RGB"); - // init luma noisevarL - const float noiseluma=(float) dnparams.luma; - const float noisevarL = (useNoiseLCurve && (denoiseMethodRgb || !isRAW)) ? (float) (SQR(((noiseluma+1.0)/125.0)*(10.+ (noiseluma+1.0)/25.0))) : (float) (SQR((noiseluma/125.0)*(1.0+ noiseluma/25.0))); - const bool denoiseLuminance = (noisevarL > 0.00001f); - //printf("NL=%f \n",noisevarL); - if(useNoiseLCurve || useNoiseCCurve) { - int hei=calclum->height; - int wid=calclum->width; - TMatrix wprofi = iccStore->workingSpaceMatrix (params->icm.working); - - const float wpi[3][3] = { - {static_cast(wprofi[0][0]),static_cast(wprofi[0][1]),static_cast(wprofi[0][2])}, - {static_cast(wprofi[1][0]),static_cast(wprofi[1][1]),static_cast(wprofi[1][2])}, - {static_cast(wprofi[2][0]),static_cast(wprofi[2][1]),static_cast(wprofi[2][2])} - }; - lumcalcBuffer = new float[hei*wid]; - lumcalc = new float*[(hei)]; - for (int i=0; ir(ii,jj); - float GL = calclum->g(ii,jj); - float BL = calclum->b(ii,jj); - // determine luminance and chrominance for noisecurves - float XL,YL,ZL; - Color::rgbxyz(RL,GL,BL,XL,YL,ZL,wpi); - Color::XYZ2Lab(XL, YL, ZL, LLum, AAum, BBum); - if(useNoiseLCurve) { - float epsi = 0.01f; - if(LLum<2.f) - LLum = 2.f;//avoid divided by zero - if(LLum>32768.f) - LLum = 32768.f; // not strictly necessary - float kinterm = epsi + noiseLCurve[xdivf(LLum,15)*500.f]; - kinterm *= 100.f; - kinterm += noiseluma; - lumcalc[ii][jj] = SQR((kinterm/125.f)*(1.f+kinterm/25.f)); - } - if(useNoiseCCurve) { - float cN = sqrtf(SQR(AAum)+SQR(BBum)); - if(cN > 100) - ccalc[ii][jj] = SQR(1.f + ponderCC*(4.f*noiseCCurve[cN / 60.f])); - else - ccalc[ii][jj] = cn100Precalc; - } - } - } - delete calclum; - calclum = NULL; - } - - const short int imheight=src->height, imwidth=src->width; - - if (dnparams.luma!=0 || dnparams.chroma!=0 || dnparams.methodmed=="Lab" || dnparams.methodmed=="Lonly" ) { - // gamma transform for input data - float gam = dnparams.gamma; - float gamthresh = 0.001f; - if(!isRAW) {//reduce gamma under 1 for Lab mode ==> TIF and JPG - if(gam < 1.9f) - gam = 1.f - (1.9f-gam)/3.f;//minimum gamma 0.7 - else if (gam >= 1.9f && gam <= 3.f) - gam = (1.4f/1.1f)*gam - 1.41818f; - } - float gamslope = exp(log((double)gamthresh)/gam)/gamthresh; - - LUTf gamcurve(65536,LUT_CLIP_BELOW); - if(denoiseMethodRgb) { - for (int i=0; i<65536; i++) { - gamcurve[i] = (Color::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) * 32768.0f; - } - } else { - for (int i=0; i<65536; i++) { - gamcurve[i] = (Color::gamman((double)i/65535.0,gam)) * 32768.0f; - } - } - - // inverse gamma transform for output data - float igam = 1.f/gam; - float igamthresh = gamthresh*gamslope; - float igamslope = 1.f/gamslope; - - LUTf igamcurve(65536,LUT_CLIP_BELOW); - if(denoiseMethodRgb) { - for (int i=0; i<65536; i++) { - igamcurve[i] = (Color::gamma((float)i/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); - } - } else { - for (int i=0; i<65536; i++) { - igamcurve[i] = (Color::gamman((float)i/32768.0f,igam) * 65535.0f); - } - } - - const float gain = pow (2.0f, float(expcomp)); - float noisevar_Ldetail = SQR((float)(SQR(100.-dnparams.Ldetail) + 50.*(100.-dnparams.Ldetail)) * TS * 0.5f); - if(settings->verbose) - printf("Denoise Lab=%i\n",settings->denoiselabgamma); - - // To avoid branches in loops we access the gammatabs by pointers - // modify arbitrary data for Lab..I have test : nothing, gamma 2.6 11 - gamma 4 5 - gamma 5.5 10 - // we can put other as gamma g=2.6 slope=11, etc. - // but noting to do with real gamma !!!: it's only for data Lab # data RGB - // finally I opted fot gamma55 and with options we can change - - LUTf *denoisegamtab; - LUTf *denoiseigamtab; - switch(settings->denoiselabgamma) { - case 0: denoisegamtab = &(Color::gammatab_26_11); - denoiseigamtab = &(Color::igammatab_26_11); - break; - case 1: denoisegamtab = &(Color::gammatab_4); - denoiseigamtab = &(Color::igammatab_4); - break; - default: denoisegamtab = &(Color::gammatab_55); - denoiseigamtab = &(Color::igammatab_55); - break; - } - - array2D tilemask_in(TS,TS); - array2D tilemask_out(TS,TS); - if(denoiseLuminance) { - const int border = MAX(2,TS/16); - for (int i=0; iTS/2 ? i-TS+1 : i)); - float vmask = (i1TS/2 ? j-TS+1 : j)); - tilemask_in[i][j] = (vmask * (j1leveldnti ==0) { - tilesize = 1024; - overlap = 128; -} -if(settings->leveldnti ==1) { - tilesize = 768; - overlap = 96; -} - int numTries = 0; - if(ponder) - printf("Tiled denoise processing caused by Automatic Multizone mode\n"); - bool memoryAllocationFailed = false; - -do { - numTries++; - if(numTries == 2) - printf("1st denoise pass failed due to insufficient memory, starting 2nd (tiled) pass now...\n"); - int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; - - Tile_calc (tilesize, overlap, (options.rgbDenoiseThreadLimit == 0 && !ponder) ? (numTries == 1 ? 0 : 2) : 2, imwidth, imheight, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip); - memoryAllocationFailed = false; - const int numtiles = numtiles_W * numtiles_H; - - //output buffer - Imagefloat * dsttmp; - if(numtiles == 1) - dsttmp = dst; - else { - dsttmp = new Imagefloat(imwidth,imheight); -#ifdef _OPENMP -#pragma omp parallel for -#endif - for(int i=0;ir(i,j) = 0.f; - dsttmp->g(i,j) = 0.f; - dsttmp->b(i,j) = 0.f; - } - } - - //now we have tile dimensions, overlaps - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - // According to FFTW-Doc 'it is safe to execute the same plan in parallel by multiple threads', so we now create 4 plans - // outside the parallel region and use them inside the parallel region. - - // calculate max size of numblox_W. - int max_numblox_W = ceil(((float)(MIN(imwidth,tilewidth)))/(offset))+2*blkrad; - // calculate min size of numblox_W. - int min_numblox_W = ceil(((float)((MIN(imwidth,((numtiles_W - 1) * tileWskip) + tilewidth) ) - ((numtiles_W - 1) * tileWskip)))/(offset))+2*blkrad; - - // these are needed only for creation of the plans and will be freed before entering the parallel loop - fftwf_plan plan_forward_blox[2]; - fftwf_plan plan_backward_blox[2]; - - if(denoiseLuminance) { - float *Lbloxtmp = (float*) fftwf_malloc(max_numblox_W*TS*TS*sizeof (float)); - float *fLbloxtmp = (float*) fftwf_malloc(max_numblox_W*TS*TS*sizeof (float)); - - int nfwd[2]={TS,TS}; - - //for DCT: - fftw_r2r_kind fwdkind[2] = {FFTW_REDFT10, FFTW_REDFT10}; - fftw_r2r_kind bwdkind[2] = {FFTW_REDFT01, FFTW_REDFT01}; - - // Creating the plans with FFTW_MEASURE instead of FFTW_ESTIMATE speeds up the execute a bit - plan_forward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, Lbloxtmp, NULL, 1, TS*TS, fLbloxtmp, NULL, 1, TS*TS, fwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT ); - plan_backward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, fLbloxtmp, NULL, 1, TS*TS, Lbloxtmp, NULL, 1, TS*TS, bwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT ); - plan_forward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, Lbloxtmp, NULL, 1, TS*TS, fLbloxtmp, NULL, 1, TS*TS, fwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT ); - plan_backward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, fLbloxtmp, NULL, 1, TS*TS, Lbloxtmp, NULL, 1, TS*TS, bwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT ); - fftwf_free ( Lbloxtmp ); - fftwf_free ( fLbloxtmp ); - } - -#ifndef _OPENMP - int numthreads = 1; -#else - // Calculate number of tiles. If less than omp_get_max_threads(), then limit num_threads to number of tiles - int numthreads = MIN(numtiles,omp_get_max_threads()); - if(options.rgbDenoiseThreadLimit > 0) - numthreads = MIN(numthreads,options.rgbDenoiseThreadLimit); -#ifdef _RT_NESTED_OPENMP - denoiseNestedLevels = omp_get_max_threads() / numthreads; - bool oldNested = omp_get_nested(); - if(denoiseNestedLevels < 2) - denoiseNestedLevels = 1; - else - omp_set_nested(true); - if(options.rgbDenoiseThreadLimit > 0) - while(denoiseNestedLevels*numthreads > options.rgbDenoiseThreadLimit) - denoiseNestedLevels--; -#endif - if(settings->verbose) - printf("RGB_denoise uses %d main thread(s) and up to %d nested thread(s) for each main thread\n",numthreads,denoiseNestedLevels); -#endif - float *LbloxArray[denoiseNestedLevels*numthreads]; - float *fLbloxArray[denoiseNestedLevels*numthreads]; - - if(numtiles > 1 && denoiseLuminance) - for(int i=0;iworkingSpaceInverseMatrix (params->icm.working); - //inverse matrix user select - const float wip[3][3] = { - {static_cast(wiprof[0][0]),static_cast(wiprof[0][1]),static_cast(wiprof[0][2])}, - {static_cast(wiprof[1][0]),static_cast(wiprof[1][1]),static_cast(wiprof[1][2])}, - {static_cast(wiprof[2][0]),static_cast(wiprof[2][1]),static_cast(wiprof[2][2])} - }; - - TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); - - const float wp[3][3] = { - {static_cast(wprof[0][0]),static_cast(wprof[0][1]),static_cast(wprof[0][2])}, - {static_cast(wprof[1][0]),static_cast(wprof[1][1]),static_cast(wprof[1][2])}, - {static_cast(wprof[2][0]),static_cast(wprof[2][1]),static_cast(wprof[2][2])} - }; - - - // begin tile processing of image -#ifdef _OPENMP -#pragma omp parallel num_threads(numthreads) if(numthreads>1) -#endif - { - int pos; - float* noisevarlum; - float* noisevarchrom; - if(numtiles == 1 && isRAW && (useNoiseCCurve || useNoiseLCurve)) { - noisevarlum = lumcalcBuffer; - noisevarchrom = ccalcBuffer; - } else { - noisevarlum = new float[((tileheight+1)/2)*((tilewidth+1)/2)]; - noisevarchrom = new float[((tileheight+1)/2)*((tilewidth+1)/2)]; - } - -#ifdef _OPENMP -#pragma omp for schedule(dynamic) collapse(2) -#endif - - for (int tiletop=0; tiletop 0.) intermred=(dnparams.redchro/10.); else intermred= (float) dnparams.redchro/7.0;//increase slower than linear for more sensit - if(dnparams.bluechro > 0.) intermblue=(dnparams.bluechro/10.); else intermblue= (float) dnparams.bluechro/7.0;//increase slower than linear for more sensit - if(ponder && kall==2){interm_med=ch_M[pos]/10.f; intermred=max_r[pos]/10.f;intermblue=max_b[pos]/10.f;} - if(ponder && kall==0){interm_med=0.01f; intermred=0.f;intermblue=0.f;} - realred = interm_med + intermred; if (realred < 0.f) realred=0.001f; - realblue = interm_med + intermblue; if (realblue < 0.f) realblue=0.001f; - const float noisevarab_r = SQR(realred); - const float noisevarab_b = SQR(realblue); - - //input L channel - array2D *Lin; - //wavelet denoised image - LabImage * labdn = new LabImage(width,height); - - //fill tile from image; convert RGB to "luma/chroma" - const float maxNoiseVarab = max(noisevarab_b,noisevarab_r); - if (isRAW) {//image is raw; use channel differences for chroma channels - - if(!denoiseMethodRgb){//lab mode - //modification Jacques feb 2013 and july 2014 -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) -#endif - for (int i=tiletop; ir(i,j); - float G_ = gain*src->g(i,j); - float B_ = gain*src->b(i,j); - - R_ = (*denoiseigamtab)[R_]; - G_ = (*denoiseigamtab)[G_]; - B_ = (*denoiseigamtab)[B_]; - - //apply gamma noise standard (slider) - R_ = R_<65535.0f ? gamcurve[R_] : (Color::gammanf(R_/65535.f, gam)*32768.0f); - G_ = G_<65535.0f ? gamcurve[G_] : (Color::gammanf(G_/65535.f, gam)*32768.0f); - B_ = B_<65535.0f ? gamcurve[B_] : (Color::gammanf(B_/65535.f, gam)*32768.0f); - - //true conversion xyz=>Lab - float X,Y,Z; - Color::rgbxyz(R_,G_,B_,X,Y,Z,wp); - - //convert to Lab - float L,a,b; - Color::XYZ2Lab(X, Y, Z, L, a, b); - - labdn->L[i1][j1] = L; - labdn->a[i1][j1] = a; - labdn->b[i1][j1] = b; - - if(((i1|j1)&1) == 0) { - if(numTries == 1) { - noisevarlum[(i1>>1)*width2+(j1>>1)] = useNoiseLCurve ? lumcalc[i>>1][j>>1] : noisevarL; - noisevarchrom[(i1>>1)*width2+(j1>>1)] = useNoiseCCurve ? maxNoiseVarab*ccalc[i>>1][j>>1] : 1.f; - } else { - noisevarlum[(i1>>1)*width2+(j1>>1)] = lumcalc[i>>1][j>>1]; - noisevarchrom[(i1>>1)*width2+(j1>>1)] = ccalc[i>>1][j>>1]; - } - } - //end chroma - } - } - } else {//RGB mode -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) -#endif - for (int i=tiletop; ir(i,j); - float Y = gain*src->g(i,j); - float Z = gain*src->b(i,j); - //conversion colorspace to determine luminance with no gamma - X = X<65535.0f ? gamcurve[X] : (Color::gamma((double)X/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - Y = Y<65535.0f ? gamcurve[Y] : (Color::gamma((double)Y/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - Z = Z<65535.0f ? gamcurve[Z] : (Color::gamma((double)Z/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - //end chroma - labdn->L[i1][j1] = Y; - labdn->a[i1][j1] = (X-Y); - labdn->b[i1][j1] = (Y-Z); - - if(((i1|j1)&1) == 0) { - if(numTries == 1) { - noisevarlum[(i1>>1)*width2+(j1>>1)] = useNoiseLCurve ? lumcalc[i>>1][j>>1] : noisevarL; - noisevarchrom[(i1>>1)*width2+(j1>>1)] = useNoiseCCurve ? maxNoiseVarab*ccalc[i>>1][j>>1] : 1.f; - } else { - noisevarlum[(i1>>1)*width2+(j1>>1)] = lumcalc[i>>1][j>>1]; - noisevarchrom[(i1>>1)*width2+(j1>>1)] = ccalc[i>>1][j>>1]; - } - } - } - } - } - } else {//image is not raw; use Lab parametrization -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) -#endif - for (int i=tiletop; ir(i,j) ;//for denoise curves - float gLum=src->g(i,j) ; - float bLum=src->b(i,j) ; - - //use gamma sRGB, not good if TIF (JPG) Output profil not with gamma sRGB (eg : gamma =1.0, or 1.8...) - //very difficult to solve ! - // solution ==> save TIF with gamma sRGB and re open - float rtmp = Color::igammatab_srgb[ src->r(i,j) ]; - float gtmp = Color::igammatab_srgb[ src->g(i,j) ]; - float btmp = Color::igammatab_srgb[ src->b(i,j) ]; - //modification Jacques feb 2013 - // gamma slider different from raw - rtmp = rtmp<65535.0f ? gamcurve[rtmp] : (Color::gamman((double)rtmp/65535.0, gam)*32768.0f); - gtmp = gtmp<65535.0f ? gamcurve[gtmp] : (Color::gamman((double)gtmp/65535.0, gam)*32768.0f); - btmp = btmp<65535.0f ? gamcurve[btmp] : (Color::gamman((double)btmp/65535.0, gam)*32768.0f); - - float X,Y,Z; - Color::rgbxyz(rtmp,gtmp,btmp,X,Y,Z,wp); - - //convert Lab - Color::XYZ2Lab(X, Y, Z, L, a, b); - labdn->L[i1][j1] = L; - labdn->a[i1][j1] = a; - labdn->b[i1][j1] = b; - - if(((i1|j1)&1) == 0) { - float Llum,alum,blum; - if(useNoiseLCurve || useNoiseCCurve) { - float XL,YL,ZL; - Color::rgbxyz(rLum,gLum,bLum,XL,YL,ZL,wp); - Color::XYZ2Lab(XL, YL, ZL, Llum, alum, blum); - } - - if(useNoiseLCurve) { - float kN = Llum; - float epsi=0.01f; - if(kN<2.f) kN=2.f; - if(kN>32768.f) kN=32768.f; - float kinterm=epsi + noiseLCurve[xdivf(kN,15)*500.f]; - float ki=kinterm*100.f; - ki+=noiseluma; - noisevarlum[(i1>>1)*width2+(j1>>1)]=SQR((ki/125.f)*(1.f+ki/25.f)); - } else { - noisevarlum[(i1>>1)*width2+(j1>>1)] = noisevarL; - } - if(useNoiseCCurve) { - float aN=alum; - float bN=blum; - float cN=sqrtf(SQR(aN)+SQR(bN)); - if(cN < 100.f) - cN=100.f;//avoid divided by zero ??? - float Cinterm=1.f + ponderCC*4.f*noiseCCurve[cN/60.f]; - noisevarchrom[(i1>>1)*width2+(j1>>1)]= maxNoiseVarab*SQR(Cinterm); - } else { - noisevarchrom[(i1>>1)*width2+(j1>>1)] = 1.f; - } - } - } - } - } - - //now perform basic wavelet denoise - //arguments 4 and 5 of wavelet decomposition are max number of wavelet decomposition levels; - //and whether to subsample the image after wavelet filtering. Subsampling is coded as - //binary 1 or 0 for each level, eg subsampling = 0 means no subsampling, 1 means subsample - //the first level only, 7 means subsample the first three levels, etc. - //actual implementation only works with subsampling set to 1 - float interm_medT = (float) dnparams.chroma/10.0; - bool execwavelet = true; - if(!denoiseLuminance && interm_medT < 0.05f && dnparams.median && (dnparams.methodmed=="Lab" || dnparams.methodmed=="Lonly")) - execwavelet=false;//do not exec wavelet if sliders luminance and chroma are very small and median need - //we considered user don't want wavelet - if(settings->leveldnautsimpl==1 && dnparams.Cmethod!="MAN") - execwavelet=true; - if(settings->leveldnautsimpl==0 && dnparams.C2method!="MANU") - execwavelet=true; - if(execwavelet) {//gain time if user choose only median sliders L <=1 slider chrom master < 1 - wavelet_decomposition* Ldecomp; - wavelet_decomposition* adecomp; - - int levwav=5; - float maxreal = max(realred, realblue); - //increase the level of wavelet if user increase much or very much sliders - if( maxreal < 8.f) levwav=5; - else if( maxreal < 10.f)levwav=6; - else if( maxreal < 15.f)levwav=7; - else levwav=8;//maximum ==> I have increase Maxlevel in cplx_wavelet_dec.h from 8 to 9 - if(nrQuality == QUALITY_HIGH) - levwav += settings->nrwavlevel;//increase level for enhanced mode - if(levwav>8) levwav=8; - int minsizetile=min(tilewidth, tileheight); - int maxlev2=8; - if(minsizetile < 256) maxlev2 = 7; - if(minsizetile < 128) maxlev2 = 6; - if(minsizetile < 64) maxlev2 = 5; - levwav=min(maxlev2,levwav); - - // if (settings->verbose) printf("levwavelet=%i noisevarA=%f noisevarB=%f \n",levwav, noisevarab_r, noisevarab_b ); - Ldecomp = new wavelet_decomposition (labdn->L[0], labdn->W, labdn->H, levwav, 1, 1, max(1,denoiseNestedLevels)); - if(Ldecomp->memoryAllocationFailed) { - memoryAllocationFailed = true; - } - float madL[8][3]; - if(!memoryAllocationFailed) { - // precalculate madL, because it's used in adecomp and bdecomp - int maxlvl = Ldecomp->maxlevel(); -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for schedule(dynamic) collapse(2) num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) -#endif - for (int lvl=0; lvllevel_W(lvl); - int Hlvl_L = Ldecomp->level_H(lvl); - - float ** WavCoeffs_L = Ldecomp->level_coeffs(lvl); - - if(!denoiseMethodRgb) { - madL[lvl][dir-1] = SQR(Mad(WavCoeffs_L[dir], Wlvl_L*Hlvl_L)); - } else { - madL[lvl][dir-1] = SQR(MadRgb(WavCoeffs_L[dir], Wlvl_L*Hlvl_L)); - } - } - } - } - - float chresid = 0.f; - float chresidtemp=0.f; - float chmaxresid = 0.f; - float chmaxresidtemp = 0.f; - - adecomp = new wavelet_decomposition (labdn->a[0], labdn->W, labdn->H,levwav, 1, 1, max(1,denoiseNestedLevels)); - if(adecomp->memoryAllocationFailed) { - memoryAllocationFailed = true; - } - if(!memoryAllocationFailed) { - if(nrQuality==QUALITY_STANDARD) { - if(!WaveletDenoiseAllAB(*Ldecomp, *adecomp, noisevarchrom, madL, noisevarab_r, useNoiseCCurve, autoch, denoiseMethodRgb ))//enhance mode - memoryAllocationFailed = true; - } else /*if(nrQuality==QUALITY_HIGH)*/ { - if(!WaveletDenoiseAll_BiShrinkAB(*Ldecomp, *adecomp, noisevarchrom, madL, noisevarab_r, useNoiseCCurve, autoch, denoiseMethodRgb ))//enhance mode - memoryAllocationFailed = true; - if(!memoryAllocationFailed) - if(!WaveletDenoiseAllAB(*Ldecomp, *adecomp, noisevarchrom, madL, noisevarab_r, useNoiseCCurve, autoch, denoiseMethodRgb )) - memoryAllocationFailed = true; - } - } - if(!memoryAllocationFailed) { - if(kall == 0) { - Noise_residualAB(*adecomp, chresid, chmaxresid, denoiseMethodRgb); - chresidtemp=chresid; - chmaxresidtemp= chmaxresid; - } - adecomp->reconstruct(labdn->a[0]); - } - delete adecomp; - if(!memoryAllocationFailed) { - wavelet_decomposition* bdecomp = new wavelet_decomposition (labdn->b[0], labdn->W, labdn->H, levwav, 1, 1, max(1,denoiseNestedLevels)); - if(bdecomp->memoryAllocationFailed) { - memoryAllocationFailed = true; - } - if(!memoryAllocationFailed) { - if(nrQuality==QUALITY_STANDARD) { - if(!WaveletDenoiseAllAB(*Ldecomp, *bdecomp, noisevarchrom, madL, noisevarab_b, useNoiseCCurve, autoch, denoiseMethodRgb ))//enhance mode - memoryAllocationFailed = true; - } else /*if(nrQuality==QUALITY_HIGH)*/ { - if(!WaveletDenoiseAll_BiShrinkAB(*Ldecomp, *bdecomp, noisevarchrom, madL, noisevarab_b, useNoiseCCurve, autoch, denoiseMethodRgb ))//enhance mode - memoryAllocationFailed = true; - if(!memoryAllocationFailed) - if(!WaveletDenoiseAllAB(*Ldecomp, *bdecomp, noisevarchrom, madL, noisevarab_b, useNoiseCCurve, autoch, denoiseMethodRgb )) - memoryAllocationFailed = true; - } - } - if(!memoryAllocationFailed) { - if(kall == 0) { - Noise_residualAB(*bdecomp, chresid, chmaxresid, denoiseMethodRgb); - chresid += chresidtemp; - chmaxresid += chmaxresidtemp; - chresid = sqrt(chresid/(6*(levwav))); - highresi = chresid + 0.66f*(sqrt(chmaxresid) - chresid);//evaluate sigma - nresi = chresid; - } - bdecomp->reconstruct(labdn->b[0]); - } - delete bdecomp; - if(!memoryAllocationFailed) { - if(denoiseLuminance) { - int edge=0; - if(nrQuality==QUALITY_STANDARD) { - if(!WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, NULL, edge))//enhance mode - memoryAllocationFailed = true; - } else /*if(nrQuality==QUALITY_HIGH)*/ { - if(!WaveletDenoiseAll_BiShrinkL(*Ldecomp, noisevarlum, madL))//enhance mode - memoryAllocationFailed = true; - if(!memoryAllocationFailed) - if(!WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, NULL, edge)) - memoryAllocationFailed = true; - } - if(!memoryAllocationFailed) { - // copy labdn->L to Lin before it gets modified by reconstruction - Lin = new array2D(width,height); -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) -#endif - for(int i=0;iL[i][j]; - - Ldecomp->reconstruct(labdn->L[0]); - } - } - } - } - delete Ldecomp; - } - - if(!memoryAllocationFailed) { - if( (metchoice==1 || metchoice==2 || metchoice==3 || metchoice==4) && dnparams.median) { - float** tmL; - int wid=labdn->W; - int hei=labdn->H; - tmL = new float*[hei]; - for (int i=0; iL, labdn->L, wid, hei, medianTypeL, dnparams.passes, denoiseNestedLevels, tmL); - if(metchoice==2 || metchoice==3 || metchoice==4) { - Median_Denoise( labdn->a, labdn->a, wid, hei, medianTypeAB, dnparams.passes, denoiseNestedLevels, tmL); - Median_Denoise( labdn->b, labdn->b, wid, hei, medianTypeAB, dnparams.passes, denoiseNestedLevels, tmL); - } - - for (int i=0; i Ldetail(width,height,ARRAY2D_CLEAR_DATA); - //pixel weight - array2D totwt(width,height,ARRAY2D_CLEAR_DATA);//weight for combining DCT blocks - if(numtiles == 1) - for(int i=0;i1) -#endif -{ -#ifdef _RT_NESTED_OPENMP - int subThread = masterThread * denoiseNestedLevels + omp_get_thread_num(); -#else - int subThread = 0; -#endif - float blurbuffer[TS*TS] ALIGNED64; - float *Lblox = LbloxArray[subThread]; - float *fLblox = fLbloxArray[subThread]; - float pBuf[width + TS + 2*blkrad*offset] ALIGNED16; - float nbrwt[TS*TS] ALIGNED64; -#ifdef _RT_NESTED_OPENMP -#pragma omp for -#endif - for (int vblk=0; vblk=height) { - rr = MAX(0,2*height-2-row); - } - - for (int j=0; jW; j++) { - datarow[j] = ((*Lin)[rr][j]-labdn->L[rr][j]); - } - - for (int j=-blkrad*offset; j<0; j++) { - datarow[j] = datarow[MIN(-j,width-1)]; - } - for (int j=width; j=0 && top+i1) -#endif - for (int i=0; iL[i][j] += Ldetail[i][j]/totwt[i][j]; //note that labdn initially stores the denoised hipass data - } - } - } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // transform denoised "Lab" to output RGB - - //calculate mask for feathering output tile overlaps - float Vmask[height+1] ALIGNED16; - float Hmask[width+1] ALIGNED16; - float newGain; - if(numtiles > 1) { - for (int i=0; i0) Vmask[i] = mask; - if (tilebottom0) Hmask[i] = mask/newGain; - if (tilerightxyz - float L = labdn->L[i1][j1]; - float a = labdn->a[i1][j1]; - float b = labdn->b[i1][j1]; - float c_h=SQR(a)+SQR(b); - if(c_h>9000000.f){ - a *= 1.f + qhighFactor*realred; - b *= 1.f + qhighFactor*realblue; - } - //convert XYZ - float X,Y,Z; - Color::Lab2XYZ(L, a, b, X, Y, Z); - //apply inverse gamma noise - float r_,g_,b_; - Color::xyz2rgb(X,Y,Z,r_,g_,b_,wip); - //inverse gamma standard (slider) - r_ = r_<32768.f ? igamcurve[r_] : (Color::gammanf(r_/32768.f, igam) * 65535.f); - g_ = g_<32768.f ? igamcurve[g_] : (Color::gammanf(g_/32768.f, igam) * 65535.f); - b_ = b_<32768.f ? igamcurve[b_] : (Color::gammanf(b_/32768.f, igam) * 65535.f); - - //readapt arbitrary gamma (inverse from beginning) - r_ = (*denoisegamtab)[r_]; - g_ = (*denoisegamtab)[g_]; - b_ = (*denoisegamtab)[b_]; - - if(numtiles == 1) { - dsttmp->r(i,j) = newGain*r_; - dsttmp->g(i,j) = newGain*g_; - dsttmp->b(i,j) = newGain*b_; - } else { - float factor = Vmask[i1]*Hmask[j1]; - dsttmp->r(i,j) += factor*r_; - dsttmp->g(i,j) += factor*g_; - dsttmp->b(i,j) += factor*b_; - } - } - } - } else {//RGB mode -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(denoiseNestedLevels) -#endif - for (int i=tiletop; ia[i1][j1])+SQR(labdn->b[i1][j1])); - if(c_h>3000.f){ - labdn->a[i1][j1]*=1.f + qhighFactor*realred/100.f; - labdn->b[i1][j1]*=1.f + qhighFactor*realblue/100.f; - } - float Y = labdn->L[i1][j1]; - float X = (labdn->a[i1][j1]) + Y; - float Z = Y - (labdn->b[i1][j1]); - - - X = X<32768.0f ? igamcurve[X] : (Color::gamma((float)X/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); - Y = Y<32768.0f ? igamcurve[Y] : (Color::gamma((float)Y/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); - Z = Z<32768.0f ? igamcurve[Z] : (Color::gamma((float)Z/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); - - if(numtiles == 1) { - dsttmp->r(i,j) = newGain*X; - dsttmp->g(i,j) = newGain*Y; - dsttmp->b(i,j) = newGain*Z; - } else { - float factor = Vmask[i1]*Hmask[j1]; - dsttmp->r(i,j) += factor*X; - dsttmp->g(i,j) += factor*Y; - dsttmp->b(i,j) += factor*Z; - } - } - } - - } - } else { -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(denoiseNestedLevels) -#endif - for (int i=tiletop; iL[i1][j1]; - float a = labdn->a[i1][j1]; - float b = labdn->b[i1][j1]; - float c_h=sqrt(SQR(a)+SQR(b)); - if(c_h>3000.f){ - a*=1.f + qhighFactor*realred/100.f; - b*=1.f + qhighFactor*realblue/100.f; - } - - float X,Y,Z; - Color::Lab2XYZ(L, a, b, X, Y, Z); - - float r_,g_,b_; - Color::xyz2rgb(X,Y,Z,r_,g_,b_,wip); - //gamma slider is different from Raw - r_ = r_<32768.0f ? igamcurve[r_] : (Color::gamman((float)r_/32768.0f, igam) * 65535.0f); - g_ = g_<32768.0f ? igamcurve[g_] : (Color::gamman((float)g_/32768.0f, igam) * 65535.0f); - b_ = b_<32768.0f ? igamcurve[b_] : (Color::gamman((float)b_/32768.0f, igam) * 65535.0f); - - if(numtiles == 1) { - dsttmp->r(i,j) = newGain*r_; - dsttmp->g(i,j) = newGain*g_; - dsttmp->b(i,j) = newGain*b_; - } else { - float factor = Vmask[i1]*Hmask[j1]; - dsttmp->r(i,j) += factor*r_; - dsttmp->g(i,j) += factor*g_; - dsttmp->b(i,j) += factor*b_; - } - } - } - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - } - delete labdn; - if(denoiseLuminance) - delete Lin; - - }//end of tile row - }//end of tile loop - if(numtiles > 1 || !isRAW || (!useNoiseCCurve && !useNoiseLCurve)) { - delete [] noisevarlum; - delete [] noisevarchrom; - } - - } - if(denoiseLuminance) { - for(int i=0;i1) { - if(!memoryAllocationFailed) - dsttmp->copyData(dst); - else if(dst != src) - src->copyData(dst); - delete dsttmp; - } - if (!isRAW && !memoryAllocationFailed) {//restore original image gamma -#ifdef _OPENMP -#pragma omp parallel for -#endif - for(int i=0;iheight;i++) - for(int j=0;jwidth;j++) { - dst->r(i,j) = Color::gammatab_srgb[ dst->r(i,j) ]; - dst->g(i,j) = Color::gammatab_srgb[ dst->g(i,j) ]; - dst->b(i,j) = Color::gammatab_srgb[ dst->b(i,j) ]; - } - } - - if(denoiseLuminance) { - // destroy the plans - fftwf_destroy_plan( plan_forward_blox[0] ); - fftwf_destroy_plan( plan_backward_blox[0] ); - fftwf_destroy_plan( plan_forward_blox[1] ); - fftwf_destroy_plan( plan_backward_blox[1] ); - fftwf_cleanup(); - } -} while(memoryAllocationFailed && numTries < 2 && (options.rgbDenoiseThreadLimit == 0) && !ponder); -if(memoryAllocationFailed) - printf("tiled denoise failed due to isufficient memory. Output is not denoised!\n"); - -} - - -//median 3x3 in complement on RGB -if(dnparams.methodmed=="RGB" && dnparams.median) { -//printf("RGB den\n"); - int wid=dst->width, hei=dst->height; - float** tm; - tm = new float*[hei]; - for (int i=0; ir(i,j),source->r(i-1,j),source->r(i+1,j),source->r(i,j+1),source->r(i,j-1),tm[i][j]);//3x3 soft - } - else - for (int j=1; jr(i,j),source->r(i-1,j),source->r(i+1,j),source->r(i,j+1),source->r(i,j-1),source->r(i-1,j-1),source->r(i-1,j+1),source->r(i+1,j-1),source->r(i+1,j+1),tm[i][j]);//3x3 - } - } - } else { -#pragma omp for - for (int i=2; ir(i,j),source->r(i-1,j),source->r(i+1,j),source->r(i,j+1),source->r(i,j-1),source->r(i-1,j-1),source->r(i-1,j+1),source->r(i+1,j-1),source->r(i+1,j+1), - source->r(i-2,j),source->r(i+2,j),source->r(i,j+2),source->r(i,j-2),source->r(i-2,j-2),source->r(i-2,j+2),source->r(i+2,j-2),source->r(i+2,j+2), - source->r(i-2,j+1),source->r(i+2,j+1),source->r(i-1,j+2),source->r(i-1,j-2),source->r(i-2,j-1),source->r(i+2,j-1),source->r(i+1,j+2),source->r(i+1,j-2), - tm[i][j]);//5x5 - } - } else - for (int j=2; jr(i,j);pp[1]=source->r(i-1,j); pp[2]=source->r(i+1,j);pp[3]=source->r(i,j+1);pp[4]=source->r(i,j-1);pp[5]=source->r(i-1,j-1);pp[6]=source->r(i-1,j+1); - pp[7]=source->r(i+1,j-1);pp[8]=source->r(i+1,j+1);pp[9]=source->r(i+2,j);pp[10]=source->r(i-2,j);pp[11]=source->r(i,j+2);pp[12]=source->r(i,j-2); - fq_sort2(pp,13); - tm[i][j]=pp[6];//5x5 soft - } - } - } -#ifdef _OPENMP -#pragma omp for nowait -#endif - for(int i = border; i < hei-border; i++ ) { - for(int j = border; j < wid-border; j++) { - dst->r(i,j) = tm[i][j]; - } - } - - if(methmed < 2) { -#pragma omp for - for (int i=1; ib(i,j),source->b(i-1,j),source->b(i+1,j),source->b(i,j+1),source->b(i,j-1),tm[i][j]); - } - else - for (int j=1; jb(i,j),source->b(i-1,j),source->b(i+1,j),source->b(i,j+1),source->b(i,j-1),source->b(i-1,j-1),source->b(i-1,j+1),source->b(i+1,j-1),source->b(i+1,j+1),tm[i][j]); - } - } - } else { -#pragma omp for - for (int i=2; ib(i,j),source->b(i-1,j),source->b(i+1,j),source->b(i,j+1),source->b(i,j-1),source->b(i-1,j-1),source->b(i-1,j+1),source->b(i+1,j-1),source->b(i+1,j+1), - source->b(i-2,j),source->b(i+2,j),source->b(i,j+2),source->b(i,j-2),source->b(i-2,j-2),source->b(i-2,j+2),source->b(i+2,j-2),source->b(i+2,j+2), - source->b(i-2,j+1),source->b(i+2,j+1),source->b(i-1,j+2),source->b(i-1,j-2),source->b(i-2,j-1),source->b(i+2,j-1),source->b(i+1,j+2),source->b(i+1,j-2), - tm[i][j]);//5x5 - } - } else - for (int j=2; jb(i,j);pp[1]=source->b(i-1,j); pp[2]=source->b(i+1,j);pp[3]=source->b(i,j+1);pp[4]=source->b(i,j-1);pp[5]=source->b(i-1,j-1);pp[6]=source->b(i-1,j+1); - pp[7]=source->b(i+1,j-1);pp[8]=source->b(i+1,j+1);pp[9]=source->b(i+2,j);pp[10]=source->b(i-2,j);pp[11]=source->b(i,j+2);pp[12]=source->b(i,j-2); - fq_sort2(pp,13); - tm[i][j]=pp[6];//5x5 soft - } - } - } - -#ifdef _OPENMP -#pragma omp for nowait -#endif - for(int i = border; i < hei-border; i++ ) { - for(int j = border; j < wid-border; j++) { - dst->b(i,j) = tm[i][j]; - } - } - - - if(methmed < 2) { -#pragma omp for - for (int i=1; ig(i,j),source->g(i-1,j),source->g(i+1,j),source->g(i,j+1),source->g(i,j-1),tm[i][j]); - } - else - for (int j=1; jg(i,j),source->g(i-1,j),source->g(i+1,j),source->g(i,j+1),source->g(i,j-1),source->g(i-1,j-1),source->g(i-1,j+1),source->g(i+1,j-1),source->g(i+1,j+1),tm[i][j]); - } - } - } else { -#pragma omp for - for (int i=2; ig(i,j),source->g(i-1,j),source->g(i+1,j),source->g(i,j+1),source->g(i,j-1),source->g(i-1,j-1),source->g(i-1,j+1),source->g(i+1,j-1),source->g(i+1,j+1), - source->g(i-2,j),source->g(i+2,j),source->g(i,j+2),source->g(i,j-2),source->g(i-2,j-2),source->g(i-2,j+2),source->g(i+2,j-2),source->g(i+2,j+2), - source->g(i-2,j+1),source->g(i+2,j+1),source->g(i-1,j+2),source->g(i-1,j-2),source->g(i-2,j-1),source->g(i+2,j-1),source->g(i+1,j+2),source->g(i+1,j-2), - tm[i][j]);//5x5 - } - } else - for (int j=2; jg(i,j);pp[1]=source->g(i-1,j); pp[2]=source->g(i+1,j);pp[3]=source->g(i,j+1);pp[4]=source->g(i,j-1);pp[5]=source->g(i-1,j-1);pp[6]=source->g(i-1,j+1); - pp[7]=source->g(i+1,j-1);pp[8]=source->g(i+1,j+1);pp[9]=source->g(i+2,j);pp[10]=source->g(i-2,j);pp[11]=source->g(i,j+2);pp[12]=source->g(i,j-2); - fq_sort2(pp,13); - tm[i][j]=pp[6];//5x5 soft - } - } - } - -#ifdef _OPENMP -#pragma omp for -#endif - for(int i = border; i < hei-border; i++ ) { - for(int j = border; j < wid-border; j++) { - dst->g(i,j) = tm[i][j]; - } - } -} -} - for (int i=0; iverbose) { - t2e.set(); - printf("Denoise performed in %d usec:\n", t2e.etime(t1e)); - } -//#endif - -}//end of main RGB_denoise - - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -SSEFUNCTION void ImProcFunctions::RGBtile_denoise (float * fLblox, int hblproc, float noisevar_Ldetail, float * nbrwt, float * blurbuffer ) //for DCT - { - int blkstart = hblproc*TS*TS; - - boxabsblur(fLblox+blkstart, nbrwt, 3, 3, TS, TS, blurbuffer);//blur neighbor weights for more robust estimation //for DCT - -#ifdef __SSE2__ - __m128 tempv; - __m128 noisevar_Ldetailv = _mm_set1_ps( noisevar_Ldetail ); - __m128 onev = _mm_set1_ps( 1.0f ); - for (int n=0; nmaxresid ) maxresid=madC; - } - } - - chresid = resid; - chmaxresid = maxresid; -} - -SSEFUNCTION bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(wavelet_decomposition &WaveletCoeffs_L, float *noisevarlum, float madL[8][3]) { - int maxlvl = min(WaveletCoeffs_L.maxlevel(),5); - const float eps = 0.01f; - - int maxWL = 0, maxHL = 0; - for (int lvl=0; lvl maxWL) - maxWL = WaveletCoeffs_L.level_W(lvl); - if(WaveletCoeffs_L.level_H(lvl) > maxHL) - maxHL = WaveletCoeffs_L.level_H(lvl); - } - bool memoryAllocationFailed = false; -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) -#endif -{ - float *buffer[3]; - buffer[0] = new (std::nothrow) float[maxWL*maxHL+32]; - buffer[1] = new (std::nothrow) float[maxWL*maxHL+64]; - buffer[2] = new (std::nothrow) float[maxWL*maxHL+96]; - if(buffer[0] == NULL || buffer[1] == NULL || buffer[2] == NULL) { - memoryAllocationFailed = true; - } - - if(!memoryAllocationFailed) { - -#ifdef _RT_NESTED_OPENMP -#pragma omp for schedule(dynamic) collapse(2) -#endif - for (int lvl=maxlvl-1; lvl>=0; lvl--) {//for levels less than max, use level diff to make edge mask - for (int dir=1; dir<4; dir++) { - int Wlvl_L = WaveletCoeffs_L.level_W(lvl); - int Hlvl_L = WaveletCoeffs_L.level_H(lvl); - - float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); - if (lvl==maxlvl-1) { - float vari[4]; - int edge=0; - ShrinkAllL(WaveletCoeffs_L, buffer, lvl, dir, noisevarlum, madL[lvl], NULL, edge ); - } else { - //simple wavelet shrinkage - float * sfave = buffer[0]+32; - float * sfaved = buffer[2]+96; - float * blurBuffer = buffer[1]+64; - - float mad_Lr = madL[lvl][dir-1]; - - float levelFactor = mad_Lr*5.f/(lvl+1); -#ifdef __SSE2__ - __m128 mad_Lv; - __m128 ninev = _mm_set1_ps( 9.0f ); - __m128 epsv = _mm_set1_ps(eps); - __m128 mag_Lv; - __m128 levelFactorv = _mm_set1_ps(levelFactor); - int coeffloc_L; - for (coeffloc_L=0; coeffloc_L=0;i--) - if(buffer[i] != NULL) - delete [] buffer[i]; - -} - return (!memoryAllocationFailed); -} - -SSEFUNCTION bool ImProcFunctions::WaveletDenoiseAll_BiShrinkAB(wavelet_decomposition &WaveletCoeffs_L, wavelet_decomposition &WaveletCoeffs_ab, - float *noisevarchrom, float madL[8][3], float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb) - { - int maxlvl = WaveletCoeffs_L.maxlevel(); - if(autoch && noisevar_ab <=0.001f) noisevar_ab=0.02f; - - float madab[8][3]; - - int maxWL = 0, maxHL = 0; - for (int lvl=0; lvl maxWL) - maxWL = WaveletCoeffs_L.level_W(lvl); - if(WaveletCoeffs_L.level_H(lvl) > maxHL) - maxHL = WaveletCoeffs_L.level_H(lvl); - } - bool memoryAllocationFailed = false; -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) -#endif -{ - float *buffer[3]; - buffer[0] = new (std::nothrow) float[maxWL*maxHL+32]; - buffer[1] = new (std::nothrow) float[maxWL*maxHL+64]; - buffer[2] = new (std::nothrow) float[maxWL*maxHL+96]; - if(buffer[0] == NULL || buffer[1] == NULL || buffer[2] == NULL) { - memoryAllocationFailed = true; - } - - if(!memoryAllocationFailed) { - - -#ifdef _RT_NESTED_OPENMP -#pragma omp for schedule(dynamic) collapse(2) -#endif - for (int lvl=0; lvl=0; lvl--) {//for levels less than max, use level diff to make edge mask - for (int dir=1; dir<4; dir++) { - int Wlvl_ab = WaveletCoeffs_ab.level_W(lvl); - int Hlvl_ab = WaveletCoeffs_ab.level_H(lvl); - - float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); - float ** WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); - if (lvl==maxlvl-1) { - ShrinkAllAB(WaveletCoeffs_L, WaveletCoeffs_ab, buffer, lvl, dir, noisevarchrom, noisevar_ab, useNoiseCCurve, autoch, denoiseMethodRgb, madL[lvl], madab[lvl], true); - } else { - //simple wavelet shrinkage - - float mad_Lr = madL[lvl][dir-1]; - float mad_abr = useNoiseCCurve ? noisevar_ab*madab[lvl][dir-1] : SQR(noisevar_ab)*madab[lvl][dir-1]; - - if (noisevar_ab>0.001f) { - -#ifdef __SSE2__ - __m128 onev = _mm_set1_ps(1.f); - __m128 mad_abrv = _mm_set1_ps(mad_abr); - __m128 rmad_Lm9v = onev / _mm_set1_ps(mad_Lr * 9.f); - __m128 mad_abv; - __m128 mag_Lv, mag_abv; - __m128 tempabv; - int coeffloc_ab; - for (coeffloc_ab=0; coeffloc_ab=0;i--) - if(buffer[i] != NULL) - delete [] buffer[i]; - -} - return (!memoryAllocationFailed); - } - - - bool ImProcFunctions::WaveletDenoiseAllL(wavelet_decomposition &WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge)//mod JD - - { - - int maxlvl = min(WaveletCoeffs_L.maxlevel(),5); - if(edge==1) maxlvl=4;//for refine denoise edge wavelet - int maxWL = 0, maxHL = 0; - for (int lvl=0; lvl maxWL) - maxWL = WaveletCoeffs_L.level_W(lvl); - if(WaveletCoeffs_L.level_H(lvl) > maxHL) - maxHL = WaveletCoeffs_L.level_H(lvl); - } - bool memoryAllocationFailed = false; -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) -#endif -{ - float *buffer[4]; - buffer[0] = new (std::nothrow) float[maxWL*maxHL+32]; - buffer[1] = new (std::nothrow) float[maxWL*maxHL+64]; - buffer[2] = new (std::nothrow) float[maxWL*maxHL+96]; - buffer[3] = new (std::nothrow) float[maxWL*maxHL+128]; - if(buffer[0] == NULL || buffer[1] == NULL || buffer[2] == NULL || buffer[3] == NULL) { - memoryAllocationFailed = true; - } - - if(!memoryAllocationFailed) { -#ifdef _RT_NESTED_OPENMP -#pragma omp for schedule(dynamic) collapse(2) -#endif - for (int lvl=0; lvl=0;i--) - if(buffer[i] != NULL) - delete [] buffer[i]; -} - return (!memoryAllocationFailed); - } - - - bool ImProcFunctions::WaveletDenoiseAllAB(wavelet_decomposition &WaveletCoeffs_L, wavelet_decomposition &WaveletCoeffs_ab, - float *noisevarchrom, float madL[8][3], float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb)//mod JD - - { - - int maxlvl = WaveletCoeffs_L.maxlevel(); - int maxWL = 0, maxHL = 0; - for (int lvl=0; lvl maxWL) - maxWL = WaveletCoeffs_L.level_W(lvl); - if(WaveletCoeffs_L.level_H(lvl) > maxHL) - maxHL = WaveletCoeffs_L.level_H(lvl); - } - bool memoryAllocationFailed = false; -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) -#endif -{ - float *buffer[3]; - buffer[0] = new (std::nothrow) float[maxWL*maxHL+32]; - buffer[1] = new (std::nothrow) float[maxWL*maxHL+64]; - buffer[2] = new (std::nothrow) float[maxWL*maxHL+96]; - if(buffer[0] == NULL || buffer[1] == NULL || buffer[2] == NULL) { - memoryAllocationFailed = true; - } - - if(!memoryAllocationFailed) { -#ifdef _RT_NESTED_OPENMP -#pragma omp for schedule(dynamic) collapse(2) -#endif - for (int lvl=0; lvl=0;i--) - if(buffer[i] != NULL) - delete [] buffer[i]; -} - return (!memoryAllocationFailed); - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -SSEFUNCTION void ImProcFunctions::ShrinkAllL(wavelet_decomposition &WaveletCoeffs_L, float **buffer, int level, int dir, - float *noisevarlum, float * madL, float * vari, int edge ) - - { - //simple wavelet shrinkage - const float eps = 0.01f; - - float * sfave = buffer[0]+32; - float * sfaved = buffer[1]+64; - float * blurBuffer = buffer[2]+96; - - int W_L = WaveletCoeffs_L.level_W(level); - int H_L = WaveletCoeffs_L.level_H(level); - - float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(level); -// printf("OK lev=%d\n",level); - float mad_L = madL[dir-1] ; - if(edge==1) { - noisevarlum = blurBuffer; // we need one buffer, but fortunately we don't have to allocate a new one because we can use blurBuffer - for (int i=0; i0.001f) { - madab = useNoiseCCurve ? madab : madab * noisevar_ab; -#ifdef __SSE2__ - __m128 onev = _mm_set1_ps(1.f); - __m128 mad_abrv = _mm_set1_ps(madab); - - __m128 rmadLm9v = onev / _mm_set1_ps(mad_L * 9.f); - __m128 mad_abv ; - __m128 mag_Lv, mag_abv; - int coeffloc_ab; - for (coeffloc_ab=0; coeffloc_ab -0.8f && noisevarhue[i][j] < 2.0f && noisevarchrom[i][j] > 10000.f) {//saturated red yellow - red_yel += noisevarchrom[i][j]; - nry++; - } - if(noisevarhue[i][j] > 0.f && noisevarhue[i][j] < 1.6f && noisevarchrom[i][j] < 10000.f) {//skin - skin_c += noisevarchrom[i][j]; - nsk++; - } - lume += noisevarlum[i][j]; - nL++; - devL += SQR(noisevarlum[i][j]-(lume/nL)); - } - } - if(nc>0) { - chromina=chro/nc; - sigma=sqrt(dev/nc); - nsknc=(float)nsk/(float)nc; - } else { - nsknc=(float)nsk; - } - if(nL>0) { - lumema=lume/nL; - sigma_L=sqrt(devL/nL); - } - if(nry>0) - redyel=red_yel/nry; - if(nsk>0) - skinc=skin_c/nsk; - } - - const float reduc = (schoice == 2) ? (float) settings->nrhigh : 1.f; - for (int dir=1; dir<4; dir++) { - float mada, madb; - if(!denoiseMethodRgb) - mada = SQR(Mad(WavCoeffs_a[dir], W_ab*H_ab)); - else - mada = SQR(MadRgb(WavCoeffs_a[dir], W_ab*H_ab)); - chred += mada; - if(mada > maxchred) - maxchred = mada; - if(mada < minchred) - minchred = mada; - maxredaut = sqrt(reduc*maxchred); - minredaut = sqrt(reduc*minchred); - - if(!denoiseMethodRgb) - madb = SQR(Mad(WavCoeffs_b[dir], W_ab*H_ab)); - else - madb = SQR(MadRgb(WavCoeffs_b[dir], W_ab*H_ab)); - chblue += madb; - if(madb > maxchblue) - maxchblue = madb; - if(madb < minchblue) - minchblue = madb; - maxblueaut = sqrt(reduc*maxchblue); - minblueaut = sqrt(reduc*minchblue); - - chau += (mada+madb); - nb++; - //here evaluation of automatic - chaut = sqrt(reduc*chau/(nb + nb)); - redaut = sqrt(reduc*chred/nb); - blueaut = sqrt(reduc*chblue/nb); - Nb = nb; - } - -} - - -void ImProcFunctions::WaveletDenoiseAll_info(int levwav, wavelet_decomposition &WaveletCoeffs_a, - wavelet_decomposition &WaveletCoeffs_b, float **noisevarlum, float **noisevarchrom, float **noisevarhue, int width, int height, float noisevar_abr, float noisevar_abb, LabImage * noi, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float &maxblueaut, float &minredaut, float &minblueaut,int schoice, bool autoch, - float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, float &maxchred, float &maxchblue, float &minchred, float &minchblue, int &nb, float &chau, float &chred, float &chblue, bool denoiseMethodRgb, bool multiThread ){ - - int maxlvl = levwav; - for (int lvl=0; lvl TIF and JPG - if(gam <1.9f) - gam=1.f - (1.9f-gam)/3.f;//minimum gamma 0.7 - else if (gam >= 1.9f && gam <= 3.f) - gam=(1.4f/1.1f)*gam - 1.41818f; - } - gamslope = exp(log((double)gamthresh)/gam)/gamthresh; - bool denoiseMethodRgb = (dnparams.dmethod=="RGB"); - if(denoiseMethodRgb) { - for (int i=0; i<65536; i++) { - gamcurve[i] = (Color::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) * 32768.0f; - } - } - else { - for (int i=0; i<65536; i++) { - gamcurve[i] = (Color::gamman((double)i/65535.0,gam)) * 32768.0f; - } - } -} - -void ImProcFunctions::calcautodn_info (float &chaut, float &delta, int Nb, int levaut, float maxmax, float lumema, float chromina, int mode, int lissage, float redyel, float skinc, float nsknc) { - - float reducdelta=1.f; - if (params->dirpyrDenoise.smethod == "shalbi") - reducdelta = (float)settings->nrhigh; - - chaut = (chaut*Nb-maxmax)/(Nb-1);//suppress maximum for chaut calcul - if ((redyel > 5000.f || skinc > 1000.f) && nsknc < 0.4f && chromina > 3000.f) - chaut *= 0.45f;//reduct action in red zone, except skin for high / med chroma - else if ((redyel>12000.f || skinc > 1200.f) && nsknc < 0.3f && chromina > 3000.f) - chaut *= 0.3f; - - if (mode==0 || mode==2) {//Preview or Auto multizone - if (chromina > 10000.f) chaut *= 0.7f;//decrease action for high chroma (visible noise) - else if (chromina > 6000.f) chaut *= 0.9f; - else if (chromina < 3000.f) chaut *= 1.2f;//increase action in low chroma==> 1.2 /==>2.0 ==> curve CC - else if (chromina < 2000.f) chaut *= 1.5f;//increase action in low chroma==> 1.5 / ==>2.7 - - if (lumema < 2500.f) chaut *= 1.3f;//increase action for low light - else if (lumema < 5000.f) chaut *= 1.2f; - else if (lumema > 20000.f) chaut *= 0.9f;//decrease for high light - } else if (mode == 1) {//auto ==> less coefficient because interaction - if (chromina > 10000.f) chaut *= 0.8f;//decrease action for high chroma (visible noise) - else if (chromina > 6000.f) chaut *= 0.9f; - else if (chromina < 3000.f) chaut *= 1.5f;//increase action in low chroma - else if (chromina < 2000.f) chaut *= 2.2f;//increase action in low chroma - if (lumema < 2500.f) chaut *= 1.2f;//increase action for low light - else if (lumema < 5000.f) chaut *= 1.1f; - else if (lumema > 20000.f) chaut *= 0.9f;//decrease for high light - } - - if(levaut==0) {//Low denoise - if(chaut > 300.f) - chaut = 0.714286f*chaut + 85.71428f; - } - - delta = maxmax-chaut; - delta *= reducdelta; - - if (lissage==1 || lissage==2) { - if (chaut < 200.f && delta < 200.f ) delta *= 0.95f; - else if (chaut < 200.f && delta < 400.f ) delta *= 0.5f; - else if (chaut < 200.f && delta >= 400.f ) delta = 200.f; - else if (chaut < 400.f && delta < 400.f ) delta *= 0.4f; - else if (chaut < 400.f && delta >= 400.f ) delta = 120.f; - else if (chaut < 550.f) delta *= 0.15f; - else if (chaut < 650.f) delta *= 0.1f; - else if (chaut >= 650.f) delta *= 0.07f; - if (mode==0 || mode==2) {//Preview or Auto multizone - if (chromina < 6000.f) delta *= 1.4f;//increase maxi - if (lumema < 5000.f) delta *= 1.4f; - } - else if (mode==1) {//Auto - if (chromina < 6000.f) delta *= 1.2f;//increase maxi - if (lumema < 5000.f) delta *= 1.2f; - } - } - if (lissage==0) { - if (chaut < 200.f && delta < 200.f ) delta *= 0.95f; - else if (chaut < 200.f && delta < 400.f ) delta *= 0.7f; - else if (chaut < 200.f && delta >= 400.f ) delta = 280.f; - else if (chaut < 400.f && delta < 400.f ) delta *= 0.6f; - else if (chaut < 400.f && delta >= 400.f ) delta = 200.f; - else if (chaut < 550.f) delta *= 0.3f; - else if (chaut < 650.f) delta *= 0.2f; - else if (chaut >= 650.f) delta *= 0.15f; - if (mode==0 || mode==2) {//Preview or Auto multizone - if (chromina < 6000.f) delta *= 1.4f;//increase maxi - if (lumema < 5000.f) delta *= 1.4f; - } - else if (mode==1) {//Auto - if (chromina < 6000.f) delta *= 1.2f;//increase maxi - if (lumema < 5000.f) delta *= 1.2f; - } - } - -} - -SSEFUNCTION void ImProcFunctions::RGB_denoise_info(Imagefloat * src, Imagefloat * provicalc, const bool isRAW, LUTf &gamcurve, float gam, float gamthresh, float gamslope, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float &maxblueaut, float &minredaut, float &minblueaut, float &nresi, float &highresi, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, bool multiThread) -{ - if ((settings->leveldnautsimpl==1 && dnparams.Cmethod == "MAN") || (settings->leveldnautsimpl==0 && dnparams.C2method == "MANU")) { - //nothing to do - return; - } - - int hei,wid; - float** lumcalc; - float** acalc; - float** bcalc; - hei=provicalc->height; - wid=provicalc->width; - TMatrix wprofi = iccStore->workingSpaceMatrix (params->icm.working); - - const float wpi[3][3] = { - {static_cast(wprofi[0][0]),static_cast(wprofi[0][1]),static_cast(wprofi[0][2])}, - {static_cast(wprofi[1][0]),static_cast(wprofi[1][1]),static_cast(wprofi[1][2])}, - {static_cast(wprofi[2][0]),static_cast(wprofi[2][1]),static_cast(wprofi[2][2])} - }; - - lumcalc = new float*[hei]; - for (int i=0; ir(ii,jj); - float GL = provicalc->g(ii,jj); - float BL = provicalc->b(ii,jj); - // determine luminance for noisecurve - float XL,YL,ZL; - Color::rgbxyz(RL,GL,BL,XL,YL,ZL,wpi); - Color::XYZ2Lab(XL, YL, ZL, LLum, AAum, BBum); - lumcalc[ii][jj]=LLum; - acalc[ii][jj]=AAum; - bcalc[ii][jj]=BBum; - } - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - const int imheight=src->height, imwidth=src->width; - - bool denoiseMethodRgb = (dnparams.dmethod == "RGB"); - - const float gain = pow (2.0f, float(expcomp)); - - int tilesize; - int overlap; - if(settings->leveldnti == 0) { - tilesize = 1024; - overlap = 128; - } - if(settings->leveldnti == 1) { - tilesize = 768; - overlap = 96; - } - - int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; - - //always no Tiles - int kall=0; - Tile_calc (tilesize, overlap, kall, imwidth, imheight, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip); - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); - const float wp[3][3] = { - {static_cast(wprof[0][0]),static_cast(wprof[0][1]),static_cast(wprof[0][2])}, - {static_cast(wprof[1][0]),static_cast(wprof[1][1]),static_cast(wprof[1][2])}, - {static_cast(wprof[2][0]),static_cast(wprof[2][1]),static_cast(wprof[2][2])} - }; - - float chau=0.f; - float chred=0.f; - float chblue=0.f; - float maxchred=0.f; - float maxchblue=0.f; - float minchred =100000000.f; - float minchblue=100000000.f; - int nb=0; - int comptlevel=0; - - // To avoid branches in loops we access the gammatabs by pointers - LUTf *denoiseigamtab; - switch(settings->denoiselabgamma) { - case 0: denoiseigamtab = &(Color::igammatab_26_11); - break; - case 1: denoiseigamtab = &(Color::igammatab_4); - break; - default: denoiseigamtab = &(Color::igammatab_55); - break; - } - - - for (int tiletop=0; tiletop 0.) - intermred = (dnparams.redchro/10.); - else - intermred = (float) dnparams.redchro/7.0;//increase slower than linear for more sensit - if(dnparams.bluechro > 0.) - intermblue =(dnparams.bluechro/10.); - else - intermblue = (float) dnparams.bluechro/7.0;//increase slower than linear for more sensit - realred = interm_med + intermred; - if (realred < 0.f) - realred = 0.001f; - realblue = interm_med + intermblue; - if (realblue < 0.f) - realblue = 0.001f; - //TODO: implement using AlignedBufferMP - //fill tile from image; convert RGB to "luma/chroma" - - if (isRAW) {//image is raw; use channel differences for chroma channels -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for if(multiThread) -#endif - for (int i=tiletop; i>1][j>>1]); - bNv = LVFU(bcalc[i>>1][j>>1]); - _mm_storeu_ps(&noisevarhue[i1>>1][j1>>1], xatan2f(bNv,aNv)); - _mm_storeu_ps(&noisevarchrom[i1>>1][j1>>1], _mm_max_ps(c100v,_mm_sqrt_ps(SQRV(aNv)+SQRV(bNv)))); - } - for (; j>1][j>>1]; - float bN = bcalc[i>>1][j>>1]; - float cN = sqrtf(SQR(aN)+SQR(bN)); - noisevarhue[i1>>1][j1>>1] = xatan2f(bN,aN); - if(cN < 100.f) - cN=100.f;//avoid divided by zero - noisevarchrom[i1>>1][j1>>1] = cN; - } -#else - for (int j=tileleft; j>1][j>>1]; - float bN = bcalc[i>>1][j>>1]; - float cN = sqrtf(SQR(aN)+SQR(bN)); - float hN = xatan2f(bN,aN); - if(cN < 100.f) - cN = 100.f;//avoid divided by zero - noisevarchrom[i1>>1][j1>>1] = cN; - noisevarhue[i1>>1][j1>>1] = hN; - } -#endif - } -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for if(multiThread) -#endif - for (int i=tiletop; i>1][j>>1]; - Llum = Llum < 2.f ? 2.f : Llum; //avoid divided by zero ? - Llum = Llum > 32768.f ? 32768.f : Llum; // not strictly necessary - noisevarlum[i1>>1][j1>>1]= Llum; - } - } - if (!denoiseMethodRgb){//lab mode, modification Jacques feb 2013 and july 2014 - -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for if(multiThread) -#endif - for (int i=tiletop; ir(i,j); - float G_ = gain*src->g(i,j); - float B_ = gain*src->b(i,j); - - R_ = (*denoiseigamtab)[R_]; - G_ = (*denoiseigamtab)[G_]; - B_ = (*denoiseigamtab)[B_]; - - //apply gamma noise standard (slider) - R_ = R_<65535.0f ? gamcurve[R_] : (Color::gamman((double)R_/65535.0, gam)*32768.0f); - G_ = G_<65535.0f ? gamcurve[G_] : (Color::gamman((double)G_/65535.0, gam)*32768.0f); - B_ = B_<65535.0f ? gamcurve[B_] : (Color::gamman((double)B_/65535.0, gam)*32768.0f); - //true conversion xyz=>Lab - float X,Y,Z; - Color::rgbxyz(R_,G_,B_,X,Y,Z,wp); - - //convert to Lab - float L,a,b; - Color::XYZ2Lab(X, Y, Z, L, a, b); - - labdn->a[i1][j1] = a; - labdn->b[i1][j1] = b; - } - } - } - else {//RGB mode - - for (int i=tiletop/*, i1=0*/; ir(i,j); - float Y = gain*src->g(i,j); - float Z = gain*src->b(i,j); - - X = X<65535.0f ? gamcurve[X] : (Color::gamma((double)X/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - Y = Y<65535.0f ? gamcurve[Y] : (Color::gamma((double)Y/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - Z = Z<65535.0f ? gamcurve[Z] : (Color::gamma((double)Z/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - - labdn->a[i1][j1] = (X-Y); - labdn->b[i1][j1] = (Y-Z); - } - } - } - - } else {//image is not raw; use Lab parametrization - for (int i=tiletop/*, i1=0*/; ir(i,j) ;//for luminance denoise curve - float gLum=src->g(i,j) ; - float bLum=src->b(i,j) ; - - //use gamma sRGB, not good if TIF (JPG) Output profil not with gamma sRGB (eg : gamma =1.0, or 1.8...) - //very difficult to solve ! - // solution ==> save TIF with gamma sRGB and re open - float rtmp = Color::igammatab_srgb[ src->r(i,j) ]; - float gtmp = Color::igammatab_srgb[ src->g(i,j) ]; - float btmp = Color::igammatab_srgb[ src->b(i,j) ]; - //modification Jacques feb 2013 - // gamma slider different from raw - rtmp = rtmp<65535.0f ? gamcurve[rtmp] : (Color::gamman((double)rtmp/65535.0, gam)*32768.0f); - gtmp = gtmp<65535.0f ? gamcurve[gtmp] : (Color::gamman((double)gtmp/65535.0, gam)*32768.0f); - btmp = btmp<65535.0f ? gamcurve[btmp] : (Color::gamman((double)btmp/65535.0, gam)*32768.0f); - - float X,Y,Z; - Color::rgbxyz(rtmp,gtmp,btmp,X,Y,Z,wp); - - //convert Lab - Color::XYZ2Lab(X, Y, Z, L, a, b); - - if(((i1|j1)&1) == 0) { - float Llum,alum,blum; - float XL,YL,ZL; - Color::rgbxyz(rLum,gLum,bLum,XL,YL,ZL,wp); - Color::XYZ2Lab(XL, YL, ZL, Llum, alum, blum); - float kN=Llum; - if(kN<2.f) kN=2.f; - if(kN>32768.f) kN=32768.f; - noisevarlum[i1>>1][j1>>1]=kN; - float aN=alum; - float bN=blum; - float hN=xatan2f(bN,aN); - float cN=sqrt(SQR(aN)+SQR(bN)); - if(cN < 100.f) cN=100.f;//avoid divided by zero - noisevarchrom[i1>>1][j1>>1]=cN; - noisevarhue[i1>>1][j1>>1]=hN; - } - labdn->a[i1][j1] = a; - labdn->b[i1][j1] = b; - } - } - } - int datalen = labdn->W * labdn->H; - - //now perform basic wavelet denoise - //last two arguments of wavelet decomposition are max number of wavelet decomposition levels; - //and whether to subsample the image after wavelet filtering. Subsampling is coded as - //binary 1 or 0 for each level, eg subsampling = 0 means no subsampling, 1 means subsample - //the first level only, 7 means subsample the first three levels, etc. - noisevarab_r = SQR(realred) + 0.01f; - noisevarab_b = SQR(realblue) + 0.01f; - - wavelet_decomposition* adecomp; - wavelet_decomposition* bdecomp; - - int schoice = 0;//shrink method - if (dnparams.smethod == "shalbi") - schoice=2; - - const int levwav=5; -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel sections if(multiThread) -#endif -{ -#ifdef _RT_NESTED_OPENMP -#pragma omp section -#endif -{ - adecomp = new wavelet_decomposition (labdn->data+datalen, labdn->W, labdn->H, levwav, 1 ); -} -#ifdef _RT_NESTED_OPENMP -#pragma omp section -#endif -{ - bdecomp = new wavelet_decomposition (labdn->data+2*datalen, labdn->W, labdn->H, levwav, 1 ); -} -} - bool autoch = dnparams.autochroma; - if(comptlevel==0) WaveletDenoiseAll_info(levwav, *adecomp, *bdecomp, noisevarlum, noisevarchrom, noisevarhue, width, height, noisevarab_r, noisevarab_b, labdn, chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, schoice, autoch, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc,maxchred, maxchblue, minchred, minchblue, nb,chau ,chred, chblue, denoiseMethodRgb, multiThread);//enhance mode - comptlevel+=1; - float chresid,chmaxredresid,chmaxblueresid; - nresi=chresid; - highresi=chresid + 0.66f*(max(chmaxredresid,chmaxblueresid) - chresid);//evaluate sigma - delete adecomp; - delete bdecomp; - delete labdn; - for (int i=0; i<(height+1)/2; i++) - delete [] noisevarlum[i]; - delete [] noisevarlum; - for (int i=0; i<(height+1)/2; i++) - delete [] noisevarchrom[i]; - delete [] noisevarchrom; - for (int i=0; i<(height+1)/2; i++) - delete [] noisevarhue[i]; - delete [] noisevarhue; - - }//end of tile row - }//end of tile loop - - for (int i=0; i +// +// +// code dated: March 9, 2012 +// +// FTblockDN.cc is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +//////////////////////////////////////////////////////////////// + +#include +#include +#include "../rtgui/threadutils.h" +#include "rtengine.h" +#include "improcfun.h" +#include "LUT.h" +#include "array2D.h" +#include "iccmatrices.h" +#include "boxblur.h" +#include "rt_math.h" +#include "mytime.h" +#include "sleef.c" +#include "opthelper.h" +#include "cplx_wavelet_dec.h" + +#ifdef _OPENMP +#include +#endif + +#define TS 64 // Tile size +#define offset 25 // shift between tiles +#define fTS ((TS/2+1)) // second dimension of Fourier tiles +#define blkrad 1 // radius of block averaging + +#define epsilon 0.001f/(TS*TS) //tolerance + +#define med2(a0,a1,a2,a3,a4,median) { \ +pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; \ +PIX_SORT(pp[0],pp[1]) ; PIX_SORT(pp[3],pp[4]) ; PIX_SORT(pp[0],pp[3]) ;\ +PIX_SORT(pp[1],pp[4]) ; PIX_SORT(pp[1],pp[2]) ; PIX_SORT(pp[2],pp[3]) ;\ +PIX_SORT(pp[1],pp[2]) ; median=pp[2] ;} + +#define med5(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,median) { \ +pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; pp[5]=a5; pp[6]=a6; pp[7]=a7; pp[8]=a8; pp[9]=a9; pp[10]=a10; pp[11]=a11; pp[12]=a12; \ +pp[13]=a13; pp[14]=a14; pp[15]=a15; pp[16]=a16; pp[17]=a17; pp[18]=a18; pp[19]=a19; pp[20]=a20; pp[21]=a21; pp[22]=a22; pp[23]=a23; pp[24]=a24; \ +PIX_SORT(pp[0], pp[1]) ; PIX_SORT(pp[3], pp[4]) ; PIX_SORT(pp[2], pp[4]) ;\ +PIX_SORT(pp[2], pp[3]) ; PIX_SORT(pp[6], pp[7]) ; PIX_SORT(pp[5], pp[7]) ;\ +PIX_SORT(pp[5], pp[6]) ; PIX_SORT(pp[9], pp[10]) ; PIX_SORT(pp[8], pp[10]) ;\ +PIX_SORT(pp[8], pp[9]) ; PIX_SORT(pp[12], pp[13]) ; PIX_SORT(pp[11], pp[13]) ;\ +PIX_SORT(pp[11], pp[12]) ; PIX_SORT(pp[15], pp[16]) ; PIX_SORT(pp[14], pp[16]) ;\ +PIX_SORT(pp[14], pp[15]) ; PIX_SORT(pp[18], pp[19]) ; PIX_SORT(pp[17], pp[19]) ;\ +PIX_SORT(pp[17], pp[18]) ; PIX_SORT(pp[21], pp[22]) ; PIX_SORT(pp[20], pp[22]) ;\ +PIX_SORT(pp[20], pp[21]) ; PIX_SORT(pp[23], pp[24]) ; PIX_SORT(pp[2], pp[5]) ;\ +PIX_SORT(pp[3], pp[6]) ; PIX_SORT(pp[0], pp[6]) ; PIX_SORT(pp[0], pp[3]) ;\ +PIX_SORT(pp[4], pp[7]) ; PIX_SORT(pp[1], pp[7]) ; PIX_SORT(pp[1], pp[4]) ;\ +PIX_SORT(pp[11], pp[14]) ; PIX_SORT(pp[8], pp[14]) ; PIX_SORT(pp[8], pp[11]) ;\ +PIX_SORT(pp[12], pp[15]) ; PIX_SORT(pp[9], pp[15]) ; PIX_SORT(pp[9], pp[12]) ;\ +PIX_SORT(pp[13], pp[16]) ; PIX_SORT(pp[10], pp[16]) ; PIX_SORT(pp[10], pp[13]) ;\ +PIX_SORT(pp[20], pp[23]) ; PIX_SORT(pp[17], pp[23]) ; PIX_SORT(pp[17], pp[20]) ;\ +PIX_SORT(pp[21], pp[24]) ; PIX_SORT(pp[18], pp[24]) ; PIX_SORT(pp[18], pp[21]) ;\ +PIX_SORT(pp[19], pp[22]) ; PIX_SORT(pp[8], pp[17]) ; PIX_SORT(pp[9], pp[18]) ;\ +PIX_SORT(pp[0], pp[18]) ; PIX_SORT(pp[0], pp[9]) ; PIX_SORT(pp[10], pp[19]) ;\ +PIX_SORT(pp[1], pp[19]) ; PIX_SORT(pp[1], pp[10]) ; PIX_SORT(pp[11], pp[20]) ;\ +PIX_SORT(pp[2], pp[20]) ; PIX_SORT(pp[2], pp[11]) ; PIX_SORT(pp[12], pp[21]) ;\ +PIX_SORT(pp[3], pp[21]) ; PIX_SORT(pp[3], pp[12]) ; PIX_SORT(pp[13], pp[22]) ;\ +PIX_SORT(pp[4], pp[22]) ; PIX_SORT(pp[4], pp[13]) ; PIX_SORT(pp[14], pp[23]) ;\ +PIX_SORT(pp[5], pp[23]) ; PIX_SORT(pp[5], pp[14]) ; PIX_SORT(pp[15], pp[24]) ;\ +PIX_SORT(pp[6], pp[24]) ; PIX_SORT(pp[6], pp[15]) ; PIX_SORT(pp[7], pp[16]) ;\ +PIX_SORT(pp[7], pp[19]) ; PIX_SORT(pp[13], pp[21]) ; PIX_SORT(pp[15], pp[23]) ;\ +PIX_SORT(pp[7], pp[13]) ; PIX_SORT(pp[7], pp[15]) ; PIX_SORT(pp[1], pp[9]) ;\ +PIX_SORT(pp[3], pp[11]) ; PIX_SORT(pp[5], pp[17]) ; PIX_SORT(pp[11], pp[17]) ;\ +PIX_SORT(pp[9], pp[17]) ; PIX_SORT(pp[4], pp[10]) ; PIX_SORT(pp[6], pp[12]) ;\ +PIX_SORT(pp[7], pp[14]) ; PIX_SORT(pp[4], pp[6]) ; PIX_SORT(pp[4], pp[7]) ;\ +PIX_SORT(pp[12], pp[14]) ; PIX_SORT(pp[10], pp[14]) ; PIX_SORT(pp[6], pp[7]) ;\ +PIX_SORT(pp[10], pp[12]) ; PIX_SORT(pp[6], pp[10]) ; PIX_SORT(pp[6], pp[17]) ;\ +PIX_SORT(pp[12], pp[17]) ; PIX_SORT(pp[7], pp[17]) ; PIX_SORT(pp[7], pp[10]) ;\ +PIX_SORT(pp[12], pp[18]) ; PIX_SORT(pp[7], pp[12]) ; PIX_SORT(pp[10], pp[18]) ;\ +PIX_SORT(pp[12], pp[20]) ; PIX_SORT(pp[10], pp[20]) ; PIX_SORT(pp[10], pp[12]) ;\ +median=pp[12];} + +#define ELEM_FLOAT_SWAP(a,b) { register float t=(a);(a)=(b);(b)=t; } + +namespace rtengine { + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + /* + Structure of the algorithm: + + 1. Compute an initial denoise of the image via undecimated wavelet transform + and universal thresholding modulated by user input. + 2. Decompose the residual image into TSxTS size tiles, shifting by 'offset' each step + (so roughly each pixel is in (TS/offset)^2 tiles); Discrete Cosine transform the tiles. + 3. Filter the DCT data to pick out patterns missed by the wavelet denoise + 4. Inverse DCT the denoised tile data and combine the tiles into a denoised output image. + + */ + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +extern const Settings* settings; + +// Median calculation using quicksort +float fq_sort2(float arr[], int n) +{ + int low = 0; + int high = n-1; + int median = (low + high) / 2; + + for (;;) { + if (high <= low) + return arr[median] ; + if (high == low + 1) { + if (arr[low] > arr[high]) + ELEM_FLOAT_SWAP(arr[low], arr[high]) ; + return arr[median] ; + } + + int middle = (low + high) / 2; + if (arr[middle] > arr[high]) ELEM_FLOAT_SWAP(arr[middle], arr[high]) ; + if (arr[low] > arr[high]) ELEM_FLOAT_SWAP(arr[low], arr[high]) ; + if (arr[middle] > arr[low]) ELEM_FLOAT_SWAP(arr[middle], arr[low]) ; + + ELEM_FLOAT_SWAP(arr[middle], arr[low+1]) ; + int ll = low + 1; + int hh = high; + + for (;;) { + do ll++; while (arr[low] > arr[ll]) ; + do hh--; while (arr[hh] > arr[low]) ; + + if (hh < ll) + break; + + ELEM_FLOAT_SWAP(arr[ll], arr[hh]) ; + } + + ELEM_FLOAT_SWAP(arr[low], arr[hh]) ; + + if (hh <= median) + low = ll; + if (hh >= median) + high = hh - 1; + } + } + +float media(float *elements, int N) +{ + + // Order elements (only half of them) + for (int i = 0; i < (N >> 1) + 1; ++i) + { + // Find position of minimum element + int min = i; + for (int j = i + 1; j < N; ++j) + if (elements[j] < elements[min]) + min = j; + // Put found minimum element in its place + float temp = elements[i]; + elements[i] = elements[min]; + elements[min] = temp; + } + // Get result - the middle element + return elements[N >> 1]; +} + +void ImProcFunctions::Median_Denoise( float **src, float **dst, const int width, const int height, const mediantype medianType, const int iterations, const int numThreads, float **buffer) +{ + int border=1, numElements, middleElement; + switch(medianType) { + case MED_3X3SOFT: + case MED_3X3STRONG: + border = 1; + break; + case MED_5X5SOFT: + border = 2; + break; + case MED_5X5STRONG: + border = 2; + break; + case MED_7X7: + border = 3; + numElements = 49; + middleElement = 24; + break; + default: // includes MED_9X9 + border = 4; + numElements = 81; + middleElement = 40; + } + + float **allocBuffer = NULL; + float **medBuffer[2]; + medBuffer[0] = src; + // we need a buffer if src == dst or if (src != dst && iterations > 1) + if(src == dst || (src != dst && iterations>1)) { + if(buffer == NULL) { // we didn't get a buufer => create one + allocBuffer = new float*[height]; + for (int i=0; i use it + medBuffer[1] = buffer; + } + } else { // we can write directly into destination + medBuffer[1] = dst; + } + + float ** medianIn, ** medianOut; + int BufferIndex = 0; + for(int iteration=1;iteration<=iterations;iteration++){ + medianIn = medBuffer[BufferIndex]; + medianOut = medBuffer[BufferIndex^1]; + + if(iteration == 1) { // upper border + for (int i=0; i1) +#endif + for (int i=border; i1) +#endif + for(int i = border; i < height-border; i++ ) { + for(int j = border; j < width-border; j++) { + dst[i][j] = medianOut[i][j]; + } + } + } + if(allocBuffer != NULL) { // we allocated memory, so let's free it now + for (int i=0; icopyData(dst); + if(calclum) { + delete calclum; + calclum = NULL; + } + + return; + } + + static MyMutex FftwMutex; + MyMutex::MyLock lock(FftwMutex); + + const nrquality nrQuality = (dnparams.smethod == "shal") ? QUALITY_STANDARD : QUALITY_HIGH;//shrink method + const float qhighFactor = (nrQuality == QUALITY_HIGH) ? 1.f/(float) settings->nrhigh : 1.0f; + const bool useNoiseCCurve = (noiseCCurve && noiseCCurve.getSum() > 5.f ); + const bool useNoiseLCurve = (noiseLCurve && noiseLCurve.getSum() >= 7.f ); + const bool autoch = (settings->leveldnautsimpl==1 && (dnparams.Cmethod=="AUT" || dnparams.Cmethod=="PRE")) || (settings->leveldnautsimpl==0 && (dnparams.C2method=="AUTO" || dnparams.C2method=="PREV")); + + float** lumcalc; + float* lumcalcBuffer; + float** ccalc; + float* ccalcBuffer; + + bool ponder=false; + float ponderCC=1.f; + if(settings->leveldnautsimpl==1 && params->dirpyrDenoise.Cmethod=="PON") {ponder=true;ponderCC=0.5f;} + if(settings->leveldnautsimpl==1 && params->dirpyrDenoise.Cmethod=="PRE") {ponderCC=0.5f;} + if(settings->leveldnautsimpl==0 && params->dirpyrDenoise.Cmethod=="PREV") {ponderCC=0.5f;} + + int metchoice=0; + if(dnparams.methodmed=="Lonly") metchoice=1; + else if(dnparams.methodmed=="Lab") metchoice=2; + else if(dnparams.methodmed=="ab") metchoice=3; + else if(dnparams.methodmed=="Lpab") metchoice=4; + + const bool denoiseMethodRgb = (dnparams.dmethod == "RGB"); + // init luma noisevarL + const float noiseluma=(float) dnparams.luma; + const float noisevarL = (useNoiseLCurve && (denoiseMethodRgb || !isRAW)) ? (float) (SQR(((noiseluma+1.0)/125.0)*(10.+ (noiseluma+1.0)/25.0))) : (float) (SQR((noiseluma/125.0)*(1.0+ noiseluma/25.0))); + const bool denoiseLuminance = (noisevarL > 0.00001f); + //printf("NL=%f \n",noisevarL); + if(useNoiseLCurve || useNoiseCCurve) { + int hei=calclum->height; + int wid=calclum->width; + TMatrix wprofi = iccStore->workingSpaceMatrix (params->icm.working); + + const float wpi[3][3] = { + {static_cast(wprofi[0][0]),static_cast(wprofi[0][1]),static_cast(wprofi[0][2])}, + {static_cast(wprofi[1][0]),static_cast(wprofi[1][1]),static_cast(wprofi[1][2])}, + {static_cast(wprofi[2][0]),static_cast(wprofi[2][1]),static_cast(wprofi[2][2])} + }; + lumcalcBuffer = new float[hei*wid]; + lumcalc = new float*[(hei)]; + for (int i=0; ir(ii,jj); + float GL = calclum->g(ii,jj); + float BL = calclum->b(ii,jj); + // determine luminance and chrominance for noisecurves + float XL,YL,ZL; + Color::rgbxyz(RL,GL,BL,XL,YL,ZL,wpi); + Color::XYZ2Lab(XL, YL, ZL, LLum, AAum, BBum); + if(useNoiseLCurve) { + float epsi = 0.01f; + if(LLum<2.f) + LLum = 2.f;//avoid divided by zero + if(LLum>32768.f) + LLum = 32768.f; // not strictly necessary + float kinterm = epsi + noiseLCurve[xdivf(LLum,15)*500.f]; + kinterm *= 100.f; + kinterm += noiseluma; + lumcalc[ii][jj] = SQR((kinterm/125.f)*(1.f+kinterm/25.f)); + } + if(useNoiseCCurve) { + float cN = sqrtf(SQR(AAum)+SQR(BBum)); + if(cN > 100) + ccalc[ii][jj] = SQR(1.f + ponderCC*(4.f*noiseCCurve[cN / 60.f])); + else + ccalc[ii][jj] = cn100Precalc; + } + } + } + delete calclum; + calclum = NULL; + } + + const short int imheight=src->height, imwidth=src->width; + + if (dnparams.luma!=0 || dnparams.chroma!=0 || dnparams.methodmed=="Lab" || dnparams.methodmed=="Lonly" ) { + // gamma transform for input data + float gam = dnparams.gamma; + float gamthresh = 0.001f; + if(!isRAW) {//reduce gamma under 1 for Lab mode ==> TIF and JPG + if(gam < 1.9f) + gam = 1.f - (1.9f-gam)/3.f;//minimum gamma 0.7 + else if (gam >= 1.9f && gam <= 3.f) + gam = (1.4f/1.1f)*gam - 1.41818f; + } + float gamslope = exp(log((double)gamthresh)/gam)/gamthresh; + + LUTf gamcurve(65536,LUT_CLIP_BELOW); + if(denoiseMethodRgb) { + for (int i=0; i<65536; i++) { + gamcurve[i] = (Color::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) * 32768.0f; + } + } else { + for (int i=0; i<65536; i++) { + gamcurve[i] = (Color::gamman((double)i/65535.0,gam)) * 32768.0f; + } + } + + // inverse gamma transform for output data + float igam = 1.f/gam; + float igamthresh = gamthresh*gamslope; + float igamslope = 1.f/gamslope; + + LUTf igamcurve(65536,LUT_CLIP_BELOW); + if(denoiseMethodRgb) { + for (int i=0; i<65536; i++) { + igamcurve[i] = (Color::gamma((float)i/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); + } + } else { + for (int i=0; i<65536; i++) { + igamcurve[i] = (Color::gamman((float)i/32768.0f,igam) * 65535.0f); + } + } + + const float gain = pow (2.0f, float(expcomp)); + float noisevar_Ldetail = SQR((float)(SQR(100.-dnparams.Ldetail) + 50.*(100.-dnparams.Ldetail)) * TS * 0.5f); + if(settings->verbose) + printf("Denoise Lab=%i\n",settings->denoiselabgamma); + + // To avoid branches in loops we access the gammatabs by pointers + // modify arbitrary data for Lab..I have test : nothing, gamma 2.6 11 - gamma 4 5 - gamma 5.5 10 + // we can put other as gamma g=2.6 slope=11, etc. + // but noting to do with real gamma !!!: it's only for data Lab # data RGB + // finally I opted fot gamma55 and with options we can change + + LUTf *denoisegamtab; + LUTf *denoiseigamtab; + switch(settings->denoiselabgamma) { + case 0: denoisegamtab = &(Color::gammatab_26_11); + denoiseigamtab = &(Color::igammatab_26_11); + break; + case 1: denoisegamtab = &(Color::gammatab_4); + denoiseigamtab = &(Color::igammatab_4); + break; + default: denoisegamtab = &(Color::gammatab_55); + denoiseigamtab = &(Color::igammatab_55); + break; + } + + array2D tilemask_in(TS,TS); + array2D tilemask_out(TS,TS); + if(denoiseLuminance) { + const int border = MAX(2,TS/16); + for (int i=0; iTS/2 ? i-TS+1 : i)); + float vmask = (i1TS/2 ? j-TS+1 : j)); + tilemask_in[i][j] = (vmask * (j1leveldnti ==0) { + tilesize = 1024; + overlap = 128; +} +if(settings->leveldnti ==1) { + tilesize = 768; + overlap = 96; +} + int numTries = 0; + if(ponder) + printf("Tiled denoise processing caused by Automatic Multizone mode\n"); + bool memoryAllocationFailed = false; + +do { + numTries++; + if(numTries == 2) + printf("1st denoise pass failed due to insufficient memory, starting 2nd (tiled) pass now...\n"); + int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; + + Tile_calc (tilesize, overlap, (options.rgbDenoiseThreadLimit == 0 && !ponder) ? (numTries == 1 ? 0 : 2) : 2, imwidth, imheight, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip); + memoryAllocationFailed = false; + const int numtiles = numtiles_W * numtiles_H; + + //output buffer + Imagefloat * dsttmp; + if(numtiles == 1) + dsttmp = dst; + else { + dsttmp = new Imagefloat(imwidth,imheight); +#ifdef _OPENMP +#pragma omp parallel for +#endif + for(int i=0;ir(i,j) = 0.f; + dsttmp->g(i,j) = 0.f; + dsttmp->b(i,j) = 0.f; + } + } + + //now we have tile dimensions, overlaps + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // According to FFTW-Doc 'it is safe to execute the same plan in parallel by multiple threads', so we now create 4 plans + // outside the parallel region and use them inside the parallel region. + + // calculate max size of numblox_W. + int max_numblox_W = ceil(((float)(MIN(imwidth,tilewidth)))/(offset))+2*blkrad; + // calculate min size of numblox_W. + int min_numblox_W = ceil(((float)((MIN(imwidth,((numtiles_W - 1) * tileWskip) + tilewidth) ) - ((numtiles_W - 1) * tileWskip)))/(offset))+2*blkrad; + + // these are needed only for creation of the plans and will be freed before entering the parallel loop + fftwf_plan plan_forward_blox[2]; + fftwf_plan plan_backward_blox[2]; + + if(denoiseLuminance) { + float *Lbloxtmp = (float*) fftwf_malloc(max_numblox_W*TS*TS*sizeof (float)); + float *fLbloxtmp = (float*) fftwf_malloc(max_numblox_W*TS*TS*sizeof (float)); + + int nfwd[2]={TS,TS}; + + //for DCT: + fftw_r2r_kind fwdkind[2] = {FFTW_REDFT10, FFTW_REDFT10}; + fftw_r2r_kind bwdkind[2] = {FFTW_REDFT01, FFTW_REDFT01}; + + // Creating the plans with FFTW_MEASURE instead of FFTW_ESTIMATE speeds up the execute a bit + plan_forward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, Lbloxtmp, NULL, 1, TS*TS, fLbloxtmp, NULL, 1, TS*TS, fwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT ); + plan_backward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, fLbloxtmp, NULL, 1, TS*TS, Lbloxtmp, NULL, 1, TS*TS, bwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT ); + plan_forward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, Lbloxtmp, NULL, 1, TS*TS, fLbloxtmp, NULL, 1, TS*TS, fwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT ); + plan_backward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, fLbloxtmp, NULL, 1, TS*TS, Lbloxtmp, NULL, 1, TS*TS, bwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT ); + fftwf_free ( Lbloxtmp ); + fftwf_free ( fLbloxtmp ); + } + +#ifndef _OPENMP + int numthreads = 1; +#else + // Calculate number of tiles. If less than omp_get_max_threads(), then limit num_threads to number of tiles + int numthreads = MIN(numtiles,omp_get_max_threads()); + if(options.rgbDenoiseThreadLimit > 0) + numthreads = MIN(numthreads,options.rgbDenoiseThreadLimit); +#ifdef _RT_NESTED_OPENMP + denoiseNestedLevels = omp_get_max_threads() / numthreads; + bool oldNested = omp_get_nested(); + if(denoiseNestedLevels < 2) + denoiseNestedLevels = 1; + else + omp_set_nested(true); + if(options.rgbDenoiseThreadLimit > 0) + while(denoiseNestedLevels*numthreads > options.rgbDenoiseThreadLimit) + denoiseNestedLevels--; +#endif + if(settings->verbose) + printf("RGB_denoise uses %d main thread(s) and up to %d nested thread(s) for each main thread\n",numthreads,denoiseNestedLevels); +#endif + float *LbloxArray[denoiseNestedLevels*numthreads]; + float *fLbloxArray[denoiseNestedLevels*numthreads]; + + if(numtiles > 1 && denoiseLuminance) + for(int i=0;iworkingSpaceInverseMatrix (params->icm.working); + //inverse matrix user select + const float wip[3][3] = { + {static_cast(wiprof[0][0]),static_cast(wiprof[0][1]),static_cast(wiprof[0][2])}, + {static_cast(wiprof[1][0]),static_cast(wiprof[1][1]),static_cast(wiprof[1][2])}, + {static_cast(wiprof[2][0]),static_cast(wiprof[2][1]),static_cast(wiprof[2][2])} + }; + + TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); + + const float wp[3][3] = { + {static_cast(wprof[0][0]),static_cast(wprof[0][1]),static_cast(wprof[0][2])}, + {static_cast(wprof[1][0]),static_cast(wprof[1][1]),static_cast(wprof[1][2])}, + {static_cast(wprof[2][0]),static_cast(wprof[2][1]),static_cast(wprof[2][2])} + }; + + + // begin tile processing of image +#ifdef _OPENMP +#pragma omp parallel num_threads(numthreads) if(numthreads>1) +#endif + { + int pos; + float* noisevarlum; + float* noisevarchrom; + if(numtiles == 1 && isRAW && (useNoiseCCurve || useNoiseLCurve)) { + noisevarlum = lumcalcBuffer; + noisevarchrom = ccalcBuffer; + } else { + noisevarlum = new float[((tileheight+1)/2)*((tilewidth+1)/2)]; + noisevarchrom = new float[((tileheight+1)/2)*((tilewidth+1)/2)]; + } + +#ifdef _OPENMP +#pragma omp for schedule(dynamic) collapse(2) +#endif + + for (int tiletop=0; tiletop 0.) intermred=(dnparams.redchro/10.); else intermred= (float) dnparams.redchro/7.0;//increase slower than linear for more sensit + if(dnparams.bluechro > 0.) intermblue=(dnparams.bluechro/10.); else intermblue= (float) dnparams.bluechro/7.0;//increase slower than linear for more sensit + if(ponder && kall==2){interm_med=ch_M[pos]/10.f; intermred=max_r[pos]/10.f;intermblue=max_b[pos]/10.f;} + if(ponder && kall==0){interm_med=0.01f; intermred=0.f;intermblue=0.f;} + realred = interm_med + intermred; if (realred < 0.f) realred=0.001f; + realblue = interm_med + intermblue; if (realblue < 0.f) realblue=0.001f; + const float noisevarab_r = SQR(realred); + const float noisevarab_b = SQR(realblue); + + //input L channel + array2D *Lin; + //wavelet denoised image + LabImage * labdn = new LabImage(width,height); + + //fill tile from image; convert RGB to "luma/chroma" + const float maxNoiseVarab = max(noisevarab_b,noisevarab_r); + if (isRAW) {//image is raw; use channel differences for chroma channels + + if(!denoiseMethodRgb){//lab mode + //modification Jacques feb 2013 and july 2014 +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) +#endif + for (int i=tiletop; ir(i,j); + float G_ = gain*src->g(i,j); + float B_ = gain*src->b(i,j); + + R_ = (*denoiseigamtab)[R_]; + G_ = (*denoiseigamtab)[G_]; + B_ = (*denoiseigamtab)[B_]; + + //apply gamma noise standard (slider) + R_ = R_<65535.0f ? gamcurve[R_] : (Color::gammanf(R_/65535.f, gam)*32768.0f); + G_ = G_<65535.0f ? gamcurve[G_] : (Color::gammanf(G_/65535.f, gam)*32768.0f); + B_ = B_<65535.0f ? gamcurve[B_] : (Color::gammanf(B_/65535.f, gam)*32768.0f); + + //true conversion xyz=>Lab + float X,Y,Z; + Color::rgbxyz(R_,G_,B_,X,Y,Z,wp); + + //convert to Lab + float L,a,b; + Color::XYZ2Lab(X, Y, Z, L, a, b); + + labdn->L[i1][j1] = L; + labdn->a[i1][j1] = a; + labdn->b[i1][j1] = b; + + if(((i1|j1)&1) == 0) { + if(numTries == 1) { + noisevarlum[(i1>>1)*width2+(j1>>1)] = useNoiseLCurve ? lumcalc[i>>1][j>>1] : noisevarL; + noisevarchrom[(i1>>1)*width2+(j1>>1)] = useNoiseCCurve ? maxNoiseVarab*ccalc[i>>1][j>>1] : 1.f; + } else { + noisevarlum[(i1>>1)*width2+(j1>>1)] = lumcalc[i>>1][j>>1]; + noisevarchrom[(i1>>1)*width2+(j1>>1)] = ccalc[i>>1][j>>1]; + } + } + //end chroma + } + } + } else {//RGB mode +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) +#endif + for (int i=tiletop; ir(i,j); + float Y = gain*src->g(i,j); + float Z = gain*src->b(i,j); + //conversion colorspace to determine luminance with no gamma + X = X<65535.0f ? gamcurve[X] : (Color::gamma((double)X/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + Y = Y<65535.0f ? gamcurve[Y] : (Color::gamma((double)Y/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + Z = Z<65535.0f ? gamcurve[Z] : (Color::gamma((double)Z/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + //end chroma + labdn->L[i1][j1] = Y; + labdn->a[i1][j1] = (X-Y); + labdn->b[i1][j1] = (Y-Z); + + if(((i1|j1)&1) == 0) { + if(numTries == 1) { + noisevarlum[(i1>>1)*width2+(j1>>1)] = useNoiseLCurve ? lumcalc[i>>1][j>>1] : noisevarL; + noisevarchrom[(i1>>1)*width2+(j1>>1)] = useNoiseCCurve ? maxNoiseVarab*ccalc[i>>1][j>>1] : 1.f; + } else { + noisevarlum[(i1>>1)*width2+(j1>>1)] = lumcalc[i>>1][j>>1]; + noisevarchrom[(i1>>1)*width2+(j1>>1)] = ccalc[i>>1][j>>1]; + } + } + } + } + } + } else {//image is not raw; use Lab parametrization +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) +#endif + for (int i=tiletop; ir(i,j) ;//for denoise curves + float gLum=src->g(i,j) ; + float bLum=src->b(i,j) ; + + //use gamma sRGB, not good if TIF (JPG) Output profil not with gamma sRGB (eg : gamma =1.0, or 1.8...) + //very difficult to solve ! + // solution ==> save TIF with gamma sRGB and re open + float rtmp = Color::igammatab_srgb[ src->r(i,j) ]; + float gtmp = Color::igammatab_srgb[ src->g(i,j) ]; + float btmp = Color::igammatab_srgb[ src->b(i,j) ]; + //modification Jacques feb 2013 + // gamma slider different from raw + rtmp = rtmp<65535.0f ? gamcurve[rtmp] : (Color::gamman((double)rtmp/65535.0, gam)*32768.0f); + gtmp = gtmp<65535.0f ? gamcurve[gtmp] : (Color::gamman((double)gtmp/65535.0, gam)*32768.0f); + btmp = btmp<65535.0f ? gamcurve[btmp] : (Color::gamman((double)btmp/65535.0, gam)*32768.0f); + + float X,Y,Z; + Color::rgbxyz(rtmp,gtmp,btmp,X,Y,Z,wp); + + //convert Lab + Color::XYZ2Lab(X, Y, Z, L, a, b); + labdn->L[i1][j1] = L; + labdn->a[i1][j1] = a; + labdn->b[i1][j1] = b; + + if(((i1|j1)&1) == 0) { + float Llum,alum,blum; + if(useNoiseLCurve || useNoiseCCurve) { + float XL,YL,ZL; + Color::rgbxyz(rLum,gLum,bLum,XL,YL,ZL,wp); + Color::XYZ2Lab(XL, YL, ZL, Llum, alum, blum); + } + + if(useNoiseLCurve) { + float kN = Llum; + float epsi=0.01f; + if(kN<2.f) kN=2.f; + if(kN>32768.f) kN=32768.f; + float kinterm=epsi + noiseLCurve[xdivf(kN,15)*500.f]; + float ki=kinterm*100.f; + ki+=noiseluma; + noisevarlum[(i1>>1)*width2+(j1>>1)]=SQR((ki/125.f)*(1.f+ki/25.f)); + } else { + noisevarlum[(i1>>1)*width2+(j1>>1)] = noisevarL; + } + if(useNoiseCCurve) { + float aN=alum; + float bN=blum; + float cN=sqrtf(SQR(aN)+SQR(bN)); + if(cN < 100.f) + cN=100.f;//avoid divided by zero ??? + float Cinterm=1.f + ponderCC*4.f*noiseCCurve[cN/60.f]; + noisevarchrom[(i1>>1)*width2+(j1>>1)]= maxNoiseVarab*SQR(Cinterm); + } else { + noisevarchrom[(i1>>1)*width2+(j1>>1)] = 1.f; + } + } + } + } + } + + //now perform basic wavelet denoise + //arguments 4 and 5 of wavelet decomposition are max number of wavelet decomposition levels; + //and whether to subsample the image after wavelet filtering. Subsampling is coded as + //binary 1 or 0 for each level, eg subsampling = 0 means no subsampling, 1 means subsample + //the first level only, 7 means subsample the first three levels, etc. + //actual implementation only works with subsampling set to 1 + float interm_medT = (float) dnparams.chroma/10.0; + bool execwavelet = true; + if(!denoiseLuminance && interm_medT < 0.05f && dnparams.median && (dnparams.methodmed=="Lab" || dnparams.methodmed=="Lonly")) + execwavelet=false;//do not exec wavelet if sliders luminance and chroma are very small and median need + //we considered user don't want wavelet + if(settings->leveldnautsimpl==1 && dnparams.Cmethod!="MAN") + execwavelet=true; + if(settings->leveldnautsimpl==0 && dnparams.C2method!="MANU") + execwavelet=true; + if(execwavelet) {//gain time if user choose only median sliders L <=1 slider chrom master < 1 + wavelet_decomposition* Ldecomp; + wavelet_decomposition* adecomp; + + int levwav=5; + float maxreal = max(realred, realblue); + //increase the level of wavelet if user increase much or very much sliders + if( maxreal < 8.f) levwav=5; + else if( maxreal < 10.f)levwav=6; + else if( maxreal < 15.f)levwav=7; + else levwav=8;//maximum ==> I have increase Maxlevel in cplx_wavelet_dec.h from 8 to 9 + if(nrQuality == QUALITY_HIGH) + levwav += settings->nrwavlevel;//increase level for enhanced mode + if(levwav>8) levwav=8; + int minsizetile=min(tilewidth, tileheight); + int maxlev2=8; + if(minsizetile < 256) maxlev2 = 7; + if(minsizetile < 128) maxlev2 = 6; + if(minsizetile < 64) maxlev2 = 5; + levwav=min(maxlev2,levwav); + + // if (settings->verbose) printf("levwavelet=%i noisevarA=%f noisevarB=%f \n",levwav, noisevarab_r, noisevarab_b ); + Ldecomp = new wavelet_decomposition (labdn->L[0], labdn->W, labdn->H, levwav, 1, 1, max(1,denoiseNestedLevels)); + if(Ldecomp->memoryAllocationFailed) { + memoryAllocationFailed = true; + } + float madL[8][3]; + if(!memoryAllocationFailed) { + // precalculate madL, because it's used in adecomp and bdecomp + int maxlvl = Ldecomp->maxlevel(); +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for schedule(dynamic) collapse(2) num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) +#endif + for (int lvl=0; lvllevel_W(lvl); + int Hlvl_L = Ldecomp->level_H(lvl); + + float ** WavCoeffs_L = Ldecomp->level_coeffs(lvl); + + if(!denoiseMethodRgb) { + madL[lvl][dir-1] = SQR(Mad(WavCoeffs_L[dir], Wlvl_L*Hlvl_L)); + } else { + madL[lvl][dir-1] = SQR(MadRgb(WavCoeffs_L[dir], Wlvl_L*Hlvl_L)); + } + } + } + } + + float chresid = 0.f; + float chresidtemp=0.f; + float chmaxresid = 0.f; + float chmaxresidtemp = 0.f; + + adecomp = new wavelet_decomposition (labdn->a[0], labdn->W, labdn->H,levwav, 1, 1, max(1,denoiseNestedLevels)); + if(adecomp->memoryAllocationFailed) { + memoryAllocationFailed = true; + } + if(!memoryAllocationFailed) { + if(nrQuality==QUALITY_STANDARD) { + if(!WaveletDenoiseAllAB(*Ldecomp, *adecomp, noisevarchrom, madL, noisevarab_r, useNoiseCCurve, autoch, denoiseMethodRgb ))//enhance mode + memoryAllocationFailed = true; + } else /*if(nrQuality==QUALITY_HIGH)*/ { + if(!WaveletDenoiseAll_BiShrinkAB(*Ldecomp, *adecomp, noisevarchrom, madL, noisevarab_r, useNoiseCCurve, autoch, denoiseMethodRgb ))//enhance mode + memoryAllocationFailed = true; + if(!memoryAllocationFailed) + if(!WaveletDenoiseAllAB(*Ldecomp, *adecomp, noisevarchrom, madL, noisevarab_r, useNoiseCCurve, autoch, denoiseMethodRgb )) + memoryAllocationFailed = true; + } + } + if(!memoryAllocationFailed) { + if(kall == 0) { + Noise_residualAB(*adecomp, chresid, chmaxresid, denoiseMethodRgb); + chresidtemp=chresid; + chmaxresidtemp= chmaxresid; + } + adecomp->reconstruct(labdn->a[0]); + } + delete adecomp; + if(!memoryAllocationFailed) { + wavelet_decomposition* bdecomp = new wavelet_decomposition (labdn->b[0], labdn->W, labdn->H, levwav, 1, 1, max(1,denoiseNestedLevels)); + if(bdecomp->memoryAllocationFailed) { + memoryAllocationFailed = true; + } + if(!memoryAllocationFailed) { + if(nrQuality==QUALITY_STANDARD) { + if(!WaveletDenoiseAllAB(*Ldecomp, *bdecomp, noisevarchrom, madL, noisevarab_b, useNoiseCCurve, autoch, denoiseMethodRgb ))//enhance mode + memoryAllocationFailed = true; + } else /*if(nrQuality==QUALITY_HIGH)*/ { + if(!WaveletDenoiseAll_BiShrinkAB(*Ldecomp, *bdecomp, noisevarchrom, madL, noisevarab_b, useNoiseCCurve, autoch, denoiseMethodRgb ))//enhance mode + memoryAllocationFailed = true; + if(!memoryAllocationFailed) + if(!WaveletDenoiseAllAB(*Ldecomp, *bdecomp, noisevarchrom, madL, noisevarab_b, useNoiseCCurve, autoch, denoiseMethodRgb )) + memoryAllocationFailed = true; + } + } + if(!memoryAllocationFailed) { + if(kall == 0) { + Noise_residualAB(*bdecomp, chresid, chmaxresid, denoiseMethodRgb); + chresid += chresidtemp; + chmaxresid += chmaxresidtemp; + chresid = sqrt(chresid/(6*(levwav))); + highresi = chresid + 0.66f*(sqrt(chmaxresid) - chresid);//evaluate sigma + nresi = chresid; + } + bdecomp->reconstruct(labdn->b[0]); + } + delete bdecomp; + if(!memoryAllocationFailed) { + if(denoiseLuminance) { + int edge=0; + if(nrQuality==QUALITY_STANDARD) { + if(!WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, NULL, edge))//enhance mode + memoryAllocationFailed = true; + } else /*if(nrQuality==QUALITY_HIGH)*/ { + if(!WaveletDenoiseAll_BiShrinkL(*Ldecomp, noisevarlum, madL))//enhance mode + memoryAllocationFailed = true; + if(!memoryAllocationFailed) + if(!WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, NULL, edge)) + memoryAllocationFailed = true; + } + if(!memoryAllocationFailed) { + // copy labdn->L to Lin before it gets modified by reconstruction + Lin = new array2D(width,height); +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) +#endif + for(int i=0;iL[i][j]; + + Ldecomp->reconstruct(labdn->L[0]); + } + } + } + } + delete Ldecomp; + } + + if(!memoryAllocationFailed) { + if( (metchoice==1 || metchoice==2 || metchoice==3 || metchoice==4) && dnparams.median) { + float** tmL; + int wid=labdn->W; + int hei=labdn->H; + tmL = new float*[hei]; + for (int i=0; iL, labdn->L, wid, hei, medianTypeL, dnparams.passes, denoiseNestedLevels, tmL); + if(metchoice==2 || metchoice==3 || metchoice==4) { + Median_Denoise( labdn->a, labdn->a, wid, hei, medianTypeAB, dnparams.passes, denoiseNestedLevels, tmL); + Median_Denoise( labdn->b, labdn->b, wid, hei, medianTypeAB, dnparams.passes, denoiseNestedLevels, tmL); + } + + for (int i=0; i Ldetail(width,height,ARRAY2D_CLEAR_DATA); + //pixel weight + array2D totwt(width,height,ARRAY2D_CLEAR_DATA);//weight for combining DCT blocks + if(numtiles == 1) + for(int i=0;i1) +#endif +{ +#ifdef _RT_NESTED_OPENMP + int subThread = masterThread * denoiseNestedLevels + omp_get_thread_num(); +#else + int subThread = 0; +#endif + float blurbuffer[TS*TS] ALIGNED64; + float *Lblox = LbloxArray[subThread]; + float *fLblox = fLbloxArray[subThread]; + float pBuf[width + TS + 2*blkrad*offset] ALIGNED16; + float nbrwt[TS*TS] ALIGNED64; +#ifdef _RT_NESTED_OPENMP +#pragma omp for +#endif + for (int vblk=0; vblk=height) { + rr = MAX(0,2*height-2-row); + } + + for (int j=0; jW; j++) { + datarow[j] = ((*Lin)[rr][j]-labdn->L[rr][j]); + } + + for (int j=-blkrad*offset; j<0; j++) { + datarow[j] = datarow[MIN(-j,width-1)]; + } + for (int j=width; j=0 && top+i1) +#endif + for (int i=0; iL[i][j] += Ldetail[i][j]/totwt[i][j]; //note that labdn initially stores the denoised hipass data + } + } + } + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // transform denoised "Lab" to output RGB + + //calculate mask for feathering output tile overlaps + float Vmask[height+1] ALIGNED16; + float Hmask[width+1] ALIGNED16; + float newGain; + if(numtiles > 1) { + for (int i=0; i0) Vmask[i] = mask; + if (tilebottom0) Hmask[i] = mask/newGain; + if (tilerightxyz + float L = labdn->L[i1][j1]; + float a = labdn->a[i1][j1]; + float b = labdn->b[i1][j1]; + float c_h=SQR(a)+SQR(b); + if(c_h>9000000.f){ + a *= 1.f + qhighFactor*realred; + b *= 1.f + qhighFactor*realblue; + } + //convert XYZ + float X,Y,Z; + Color::Lab2XYZ(L, a, b, X, Y, Z); + //apply inverse gamma noise + float r_,g_,b_; + Color::xyz2rgb(X,Y,Z,r_,g_,b_,wip); + //inverse gamma standard (slider) + r_ = r_<32768.f ? igamcurve[r_] : (Color::gammanf(r_/32768.f, igam) * 65535.f); + g_ = g_<32768.f ? igamcurve[g_] : (Color::gammanf(g_/32768.f, igam) * 65535.f); + b_ = b_<32768.f ? igamcurve[b_] : (Color::gammanf(b_/32768.f, igam) * 65535.f); + + //readapt arbitrary gamma (inverse from beginning) + r_ = (*denoisegamtab)[r_]; + g_ = (*denoisegamtab)[g_]; + b_ = (*denoisegamtab)[b_]; + + if(numtiles == 1) { + dsttmp->r(i,j) = newGain*r_; + dsttmp->g(i,j) = newGain*g_; + dsttmp->b(i,j) = newGain*b_; + } else { + float factor = Vmask[i1]*Hmask[j1]; + dsttmp->r(i,j) += factor*r_; + dsttmp->g(i,j) += factor*g_; + dsttmp->b(i,j) += factor*b_; + } + } + } + } else {//RGB mode +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(denoiseNestedLevels) +#endif + for (int i=tiletop; ia[i1][j1])+SQR(labdn->b[i1][j1])); + if(c_h>3000.f){ + labdn->a[i1][j1]*=1.f + qhighFactor*realred/100.f; + labdn->b[i1][j1]*=1.f + qhighFactor*realblue/100.f; + } + float Y = labdn->L[i1][j1]; + float X = (labdn->a[i1][j1]) + Y; + float Z = Y - (labdn->b[i1][j1]); + + + X = X<32768.0f ? igamcurve[X] : (Color::gamma((float)X/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); + Y = Y<32768.0f ? igamcurve[Y] : (Color::gamma((float)Y/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); + Z = Z<32768.0f ? igamcurve[Z] : (Color::gamma((float)Z/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); + + if(numtiles == 1) { + dsttmp->r(i,j) = newGain*X; + dsttmp->g(i,j) = newGain*Y; + dsttmp->b(i,j) = newGain*Z; + } else { + float factor = Vmask[i1]*Hmask[j1]; + dsttmp->r(i,j) += factor*X; + dsttmp->g(i,j) += factor*Y; + dsttmp->b(i,j) += factor*Z; + } + } + } + + } + } else { +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(denoiseNestedLevels) +#endif + for (int i=tiletop; iL[i1][j1]; + float a = labdn->a[i1][j1]; + float b = labdn->b[i1][j1]; + float c_h=sqrt(SQR(a)+SQR(b)); + if(c_h>3000.f){ + a*=1.f + qhighFactor*realred/100.f; + b*=1.f + qhighFactor*realblue/100.f; + } + + float X,Y,Z; + Color::Lab2XYZ(L, a, b, X, Y, Z); + + float r_,g_,b_; + Color::xyz2rgb(X,Y,Z,r_,g_,b_,wip); + //gamma slider is different from Raw + r_ = r_<32768.0f ? igamcurve[r_] : (Color::gamman((float)r_/32768.0f, igam) * 65535.0f); + g_ = g_<32768.0f ? igamcurve[g_] : (Color::gamman((float)g_/32768.0f, igam) * 65535.0f); + b_ = b_<32768.0f ? igamcurve[b_] : (Color::gamman((float)b_/32768.0f, igam) * 65535.0f); + + if(numtiles == 1) { + dsttmp->r(i,j) = newGain*r_; + dsttmp->g(i,j) = newGain*g_; + dsttmp->b(i,j) = newGain*b_; + } else { + float factor = Vmask[i1]*Hmask[j1]; + dsttmp->r(i,j) += factor*r_; + dsttmp->g(i,j) += factor*g_; + dsttmp->b(i,j) += factor*b_; + } + } + } + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + } + delete labdn; + if(denoiseLuminance) + delete Lin; + + }//end of tile row + }//end of tile loop + if(numtiles > 1 || !isRAW || (!useNoiseCCurve && !useNoiseLCurve)) { + delete [] noisevarlum; + delete [] noisevarchrom; + } + + } + if(denoiseLuminance) { + for(int i=0;i1) { + if(!memoryAllocationFailed) + dsttmp->copyData(dst); + else if(dst != src) + src->copyData(dst); + delete dsttmp; + } + if (!isRAW && !memoryAllocationFailed) {//restore original image gamma +#ifdef _OPENMP +#pragma omp parallel for +#endif + for(int i=0;iheight;i++) + for(int j=0;jwidth;j++) { + dst->r(i,j) = Color::gammatab_srgb[ dst->r(i,j) ]; + dst->g(i,j) = Color::gammatab_srgb[ dst->g(i,j) ]; + dst->b(i,j) = Color::gammatab_srgb[ dst->b(i,j) ]; + } + } + + if(denoiseLuminance) { + // destroy the plans + fftwf_destroy_plan( plan_forward_blox[0] ); + fftwf_destroy_plan( plan_backward_blox[0] ); + fftwf_destroy_plan( plan_forward_blox[1] ); + fftwf_destroy_plan( plan_backward_blox[1] ); + fftwf_cleanup(); + } +} while(memoryAllocationFailed && numTries < 2 && (options.rgbDenoiseThreadLimit == 0) && !ponder); +if(memoryAllocationFailed) + printf("tiled denoise failed due to isufficient memory. Output is not denoised!\n"); + +} + + +//median 3x3 in complement on RGB +if(dnparams.methodmed=="RGB" && dnparams.median) { +//printf("RGB den\n"); + int wid=dst->width, hei=dst->height; + float** tm; + tm = new float*[hei]; + for (int i=0; ir(i,j),source->r(i-1,j),source->r(i+1,j),source->r(i,j+1),source->r(i,j-1),tm[i][j]);//3x3 soft + } + else + for (int j=1; jr(i,j),source->r(i-1,j),source->r(i+1,j),source->r(i,j+1),source->r(i,j-1),source->r(i-1,j-1),source->r(i-1,j+1),source->r(i+1,j-1),source->r(i+1,j+1),tm[i][j]);//3x3 + } + } + } else { +#pragma omp for + for (int i=2; ir(i,j),source->r(i-1,j),source->r(i+1,j),source->r(i,j+1),source->r(i,j-1),source->r(i-1,j-1),source->r(i-1,j+1),source->r(i+1,j-1),source->r(i+1,j+1), + source->r(i-2,j),source->r(i+2,j),source->r(i,j+2),source->r(i,j-2),source->r(i-2,j-2),source->r(i-2,j+2),source->r(i+2,j-2),source->r(i+2,j+2), + source->r(i-2,j+1),source->r(i+2,j+1),source->r(i-1,j+2),source->r(i-1,j-2),source->r(i-2,j-1),source->r(i+2,j-1),source->r(i+1,j+2),source->r(i+1,j-2), + tm[i][j]);//5x5 + } + } else + for (int j=2; jr(i,j);pp[1]=source->r(i-1,j); pp[2]=source->r(i+1,j);pp[3]=source->r(i,j+1);pp[4]=source->r(i,j-1);pp[5]=source->r(i-1,j-1);pp[6]=source->r(i-1,j+1); + pp[7]=source->r(i+1,j-1);pp[8]=source->r(i+1,j+1);pp[9]=source->r(i+2,j);pp[10]=source->r(i-2,j);pp[11]=source->r(i,j+2);pp[12]=source->r(i,j-2); + fq_sort2(pp,13); + tm[i][j]=pp[6];//5x5 soft + } + } + } +#ifdef _OPENMP +#pragma omp for nowait +#endif + for(int i = border; i < hei-border; i++ ) { + for(int j = border; j < wid-border; j++) { + dst->r(i,j) = tm[i][j]; + } + } + + if(methmed < 2) { +#pragma omp for + for (int i=1; ib(i,j),source->b(i-1,j),source->b(i+1,j),source->b(i,j+1),source->b(i,j-1),tm[i][j]); + } + else + for (int j=1; jb(i,j),source->b(i-1,j),source->b(i+1,j),source->b(i,j+1),source->b(i,j-1),source->b(i-1,j-1),source->b(i-1,j+1),source->b(i+1,j-1),source->b(i+1,j+1),tm[i][j]); + } + } + } else { +#pragma omp for + for (int i=2; ib(i,j),source->b(i-1,j),source->b(i+1,j),source->b(i,j+1),source->b(i,j-1),source->b(i-1,j-1),source->b(i-1,j+1),source->b(i+1,j-1),source->b(i+1,j+1), + source->b(i-2,j),source->b(i+2,j),source->b(i,j+2),source->b(i,j-2),source->b(i-2,j-2),source->b(i-2,j+2),source->b(i+2,j-2),source->b(i+2,j+2), + source->b(i-2,j+1),source->b(i+2,j+1),source->b(i-1,j+2),source->b(i-1,j-2),source->b(i-2,j-1),source->b(i+2,j-1),source->b(i+1,j+2),source->b(i+1,j-2), + tm[i][j]);//5x5 + } + } else + for (int j=2; jb(i,j);pp[1]=source->b(i-1,j); pp[2]=source->b(i+1,j);pp[3]=source->b(i,j+1);pp[4]=source->b(i,j-1);pp[5]=source->b(i-1,j-1);pp[6]=source->b(i-1,j+1); + pp[7]=source->b(i+1,j-1);pp[8]=source->b(i+1,j+1);pp[9]=source->b(i+2,j);pp[10]=source->b(i-2,j);pp[11]=source->b(i,j+2);pp[12]=source->b(i,j-2); + fq_sort2(pp,13); + tm[i][j]=pp[6];//5x5 soft + } + } + } + +#ifdef _OPENMP +#pragma omp for nowait +#endif + for(int i = border; i < hei-border; i++ ) { + for(int j = border; j < wid-border; j++) { + dst->b(i,j) = tm[i][j]; + } + } + + + if(methmed < 2) { +#pragma omp for + for (int i=1; ig(i,j),source->g(i-1,j),source->g(i+1,j),source->g(i,j+1),source->g(i,j-1),tm[i][j]); + } + else + for (int j=1; jg(i,j),source->g(i-1,j),source->g(i+1,j),source->g(i,j+1),source->g(i,j-1),source->g(i-1,j-1),source->g(i-1,j+1),source->g(i+1,j-1),source->g(i+1,j+1),tm[i][j]); + } + } + } else { +#pragma omp for + for (int i=2; ig(i,j),source->g(i-1,j),source->g(i+1,j),source->g(i,j+1),source->g(i,j-1),source->g(i-1,j-1),source->g(i-1,j+1),source->g(i+1,j-1),source->g(i+1,j+1), + source->g(i-2,j),source->g(i+2,j),source->g(i,j+2),source->g(i,j-2),source->g(i-2,j-2),source->g(i-2,j+2),source->g(i+2,j-2),source->g(i+2,j+2), + source->g(i-2,j+1),source->g(i+2,j+1),source->g(i-1,j+2),source->g(i-1,j-2),source->g(i-2,j-1),source->g(i+2,j-1),source->g(i+1,j+2),source->g(i+1,j-2), + tm[i][j]);//5x5 + } + } else + for (int j=2; jg(i,j);pp[1]=source->g(i-1,j); pp[2]=source->g(i+1,j);pp[3]=source->g(i,j+1);pp[4]=source->g(i,j-1);pp[5]=source->g(i-1,j-1);pp[6]=source->g(i-1,j+1); + pp[7]=source->g(i+1,j-1);pp[8]=source->g(i+1,j+1);pp[9]=source->g(i+2,j);pp[10]=source->g(i-2,j);pp[11]=source->g(i,j+2);pp[12]=source->g(i,j-2); + fq_sort2(pp,13); + tm[i][j]=pp[6];//5x5 soft + } + } + } + +#ifdef _OPENMP +#pragma omp for +#endif + for(int i = border; i < hei-border; i++ ) { + for(int j = border; j < wid-border; j++) { + dst->g(i,j) = tm[i][j]; + } + } +} +} + for (int i=0; iverbose) { + t2e.set(); + printf("Denoise performed in %d usec:\n", t2e.etime(t1e)); + } +//#endif + +}//end of main RGB_denoise + + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +SSEFUNCTION void ImProcFunctions::RGBtile_denoise (float * fLblox, int hblproc, float noisevar_Ldetail, float * nbrwt, float * blurbuffer ) //for DCT + { + int blkstart = hblproc*TS*TS; + + boxabsblur(fLblox+blkstart, nbrwt, 3, 3, TS, TS, blurbuffer);//blur neighbor weights for more robust estimation //for DCT + +#ifdef __SSE2__ + __m128 tempv; + __m128 noisevar_Ldetailv = _mm_set1_ps( noisevar_Ldetail ); + __m128 onev = _mm_set1_ps( 1.0f ); + for (int n=0; nmaxresid ) maxresid=madC; + } + } + + chresid = resid; + chmaxresid = maxresid; +} + +SSEFUNCTION bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(wavelet_decomposition &WaveletCoeffs_L, float *noisevarlum, float madL[8][3]) { + int maxlvl = min(WaveletCoeffs_L.maxlevel(),5); + const float eps = 0.01f; + + int maxWL = 0, maxHL = 0; + for (int lvl=0; lvl maxWL) + maxWL = WaveletCoeffs_L.level_W(lvl); + if(WaveletCoeffs_L.level_H(lvl) > maxHL) + maxHL = WaveletCoeffs_L.level_H(lvl); + } + bool memoryAllocationFailed = false; +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) +#endif +{ + float *buffer[3]; + buffer[0] = new (std::nothrow) float[maxWL*maxHL+32]; + buffer[1] = new (std::nothrow) float[maxWL*maxHL+64]; + buffer[2] = new (std::nothrow) float[maxWL*maxHL+96]; + if(buffer[0] == NULL || buffer[1] == NULL || buffer[2] == NULL) { + memoryAllocationFailed = true; + } + + if(!memoryAllocationFailed) { + +#ifdef _RT_NESTED_OPENMP +#pragma omp for schedule(dynamic) collapse(2) +#endif + for (int lvl=maxlvl-1; lvl>=0; lvl--) {//for levels less than max, use level diff to make edge mask + for (int dir=1; dir<4; dir++) { + int Wlvl_L = WaveletCoeffs_L.level_W(lvl); + int Hlvl_L = WaveletCoeffs_L.level_H(lvl); + + float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); + if (lvl==maxlvl-1) { + float vari[4]; + int edge=0; + ShrinkAllL(WaveletCoeffs_L, buffer, lvl, dir, noisevarlum, madL[lvl], NULL, edge ); + } else { + //simple wavelet shrinkage + float * sfave = buffer[0]+32; + float * sfaved = buffer[2]+96; + float * blurBuffer = buffer[1]+64; + + float mad_Lr = madL[lvl][dir-1]; + + float levelFactor = mad_Lr*5.f/(lvl+1); +#ifdef __SSE2__ + __m128 mad_Lv; + __m128 ninev = _mm_set1_ps( 9.0f ); + __m128 epsv = _mm_set1_ps(eps); + __m128 mag_Lv; + __m128 levelFactorv = _mm_set1_ps(levelFactor); + int coeffloc_L; + for (coeffloc_L=0; coeffloc_L=0;i--) + if(buffer[i] != NULL) + delete [] buffer[i]; + +} + return (!memoryAllocationFailed); +} + +SSEFUNCTION bool ImProcFunctions::WaveletDenoiseAll_BiShrinkAB(wavelet_decomposition &WaveletCoeffs_L, wavelet_decomposition &WaveletCoeffs_ab, + float *noisevarchrom, float madL[8][3], float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb) + { + int maxlvl = WaveletCoeffs_L.maxlevel(); + if(autoch && noisevar_ab <=0.001f) noisevar_ab=0.02f; + + float madab[8][3]; + + int maxWL = 0, maxHL = 0; + for (int lvl=0; lvl maxWL) + maxWL = WaveletCoeffs_L.level_W(lvl); + if(WaveletCoeffs_L.level_H(lvl) > maxHL) + maxHL = WaveletCoeffs_L.level_H(lvl); + } + bool memoryAllocationFailed = false; +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) +#endif +{ + float *buffer[3]; + buffer[0] = new (std::nothrow) float[maxWL*maxHL+32]; + buffer[1] = new (std::nothrow) float[maxWL*maxHL+64]; + buffer[2] = new (std::nothrow) float[maxWL*maxHL+96]; + if(buffer[0] == NULL || buffer[1] == NULL || buffer[2] == NULL) { + memoryAllocationFailed = true; + } + + if(!memoryAllocationFailed) { + + +#ifdef _RT_NESTED_OPENMP +#pragma omp for schedule(dynamic) collapse(2) +#endif + for (int lvl=0; lvl=0; lvl--) {//for levels less than max, use level diff to make edge mask + for (int dir=1; dir<4; dir++) { + int Wlvl_ab = WaveletCoeffs_ab.level_W(lvl); + int Hlvl_ab = WaveletCoeffs_ab.level_H(lvl); + + float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl); + float ** WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); + if (lvl==maxlvl-1) { + ShrinkAllAB(WaveletCoeffs_L, WaveletCoeffs_ab, buffer, lvl, dir, noisevarchrom, noisevar_ab, useNoiseCCurve, autoch, denoiseMethodRgb, madL[lvl], madab[lvl], true); + } else { + //simple wavelet shrinkage + + float mad_Lr = madL[lvl][dir-1]; + float mad_abr = useNoiseCCurve ? noisevar_ab*madab[lvl][dir-1] : SQR(noisevar_ab)*madab[lvl][dir-1]; + + if (noisevar_ab>0.001f) { + +#ifdef __SSE2__ + __m128 onev = _mm_set1_ps(1.f); + __m128 mad_abrv = _mm_set1_ps(mad_abr); + __m128 rmad_Lm9v = onev / _mm_set1_ps(mad_Lr * 9.f); + __m128 mad_abv; + __m128 mag_Lv, mag_abv; + __m128 tempabv; + int coeffloc_ab; + for (coeffloc_ab=0; coeffloc_ab=0;i--) + if(buffer[i] != NULL) + delete [] buffer[i]; + +} + return (!memoryAllocationFailed); + } + + + bool ImProcFunctions::WaveletDenoiseAllL(wavelet_decomposition &WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge)//mod JD + + { + + int maxlvl = min(WaveletCoeffs_L.maxlevel(),5); + if(edge==1) maxlvl=4;//for refine denoise edge wavelet + int maxWL = 0, maxHL = 0; + for (int lvl=0; lvl maxWL) + maxWL = WaveletCoeffs_L.level_W(lvl); + if(WaveletCoeffs_L.level_H(lvl) > maxHL) + maxHL = WaveletCoeffs_L.level_H(lvl); + } + bool memoryAllocationFailed = false; +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) +#endif +{ + float *buffer[4]; + buffer[0] = new (std::nothrow) float[maxWL*maxHL+32]; + buffer[1] = new (std::nothrow) float[maxWL*maxHL+64]; + buffer[2] = new (std::nothrow) float[maxWL*maxHL+96]; + buffer[3] = new (std::nothrow) float[maxWL*maxHL+128]; + if(buffer[0] == NULL || buffer[1] == NULL || buffer[2] == NULL || buffer[3] == NULL) { + memoryAllocationFailed = true; + } + + if(!memoryAllocationFailed) { +#ifdef _RT_NESTED_OPENMP +#pragma omp for schedule(dynamic) collapse(2) +#endif + for (int lvl=0; lvl=0;i--) + if(buffer[i] != NULL) + delete [] buffer[i]; +} + return (!memoryAllocationFailed); + } + + + bool ImProcFunctions::WaveletDenoiseAllAB(wavelet_decomposition &WaveletCoeffs_L, wavelet_decomposition &WaveletCoeffs_ab, + float *noisevarchrom, float madL[8][3], float noisevar_ab, const bool useNoiseCCurve, bool autoch, bool denoiseMethodRgb)//mod JD + + { + + int maxlvl = WaveletCoeffs_L.maxlevel(); + int maxWL = 0, maxHL = 0; + for (int lvl=0; lvl maxWL) + maxWL = WaveletCoeffs_L.level_W(lvl); + if(WaveletCoeffs_L.level_H(lvl) > maxHL) + maxHL = WaveletCoeffs_L.level_H(lvl); + } + bool memoryAllocationFailed = false; +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel num_threads(denoiseNestedLevels) if(denoiseNestedLevels>1) +#endif +{ + float *buffer[3]; + buffer[0] = new (std::nothrow) float[maxWL*maxHL+32]; + buffer[1] = new (std::nothrow) float[maxWL*maxHL+64]; + buffer[2] = new (std::nothrow) float[maxWL*maxHL+96]; + if(buffer[0] == NULL || buffer[1] == NULL || buffer[2] == NULL) { + memoryAllocationFailed = true; + } + + if(!memoryAllocationFailed) { +#ifdef _RT_NESTED_OPENMP +#pragma omp for schedule(dynamic) collapse(2) +#endif + for (int lvl=0; lvl=0;i--) + if(buffer[i] != NULL) + delete [] buffer[i]; +} + return (!memoryAllocationFailed); + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +SSEFUNCTION void ImProcFunctions::ShrinkAllL(wavelet_decomposition &WaveletCoeffs_L, float **buffer, int level, int dir, + float *noisevarlum, float * madL, float * vari, int edge ) + + { + //simple wavelet shrinkage + const float eps = 0.01f; + + float * sfave = buffer[0]+32; + float * sfaved = buffer[1]+64; + float * blurBuffer = buffer[2]+96; + + int W_L = WaveletCoeffs_L.level_W(level); + int H_L = WaveletCoeffs_L.level_H(level); + + float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(level); +// printf("OK lev=%d\n",level); + float mad_L = madL[dir-1] ; + if(edge==1) { + noisevarlum = blurBuffer; // we need one buffer, but fortunately we don't have to allocate a new one because we can use blurBuffer + for (int i=0; i0.001f) { + madab = useNoiseCCurve ? madab : madab * noisevar_ab; +#ifdef __SSE2__ + __m128 onev = _mm_set1_ps(1.f); + __m128 mad_abrv = _mm_set1_ps(madab); + + __m128 rmadLm9v = onev / _mm_set1_ps(mad_L * 9.f); + __m128 mad_abv ; + __m128 mag_Lv, mag_abv; + int coeffloc_ab; + for (coeffloc_ab=0; coeffloc_ab -0.8f && noisevarhue[i][j] < 2.0f && noisevarchrom[i][j] > 10000.f) {//saturated red yellow + red_yel += noisevarchrom[i][j]; + nry++; + } + if(noisevarhue[i][j] > 0.f && noisevarhue[i][j] < 1.6f && noisevarchrom[i][j] < 10000.f) {//skin + skin_c += noisevarchrom[i][j]; + nsk++; + } + lume += noisevarlum[i][j]; + nL++; + devL += SQR(noisevarlum[i][j]-(lume/nL)); + } + } + if(nc>0) { + chromina=chro/nc; + sigma=sqrt(dev/nc); + nsknc=(float)nsk/(float)nc; + } else { + nsknc=(float)nsk; + } + if(nL>0) { + lumema=lume/nL; + sigma_L=sqrt(devL/nL); + } + if(nry>0) + redyel=red_yel/nry; + if(nsk>0) + skinc=skin_c/nsk; + } + + const float reduc = (schoice == 2) ? (float) settings->nrhigh : 1.f; + for (int dir=1; dir<4; dir++) { + float mada, madb; + if(!denoiseMethodRgb) + mada = SQR(Mad(WavCoeffs_a[dir], W_ab*H_ab)); + else + mada = SQR(MadRgb(WavCoeffs_a[dir], W_ab*H_ab)); + chred += mada; + if(mada > maxchred) + maxchred = mada; + if(mada < minchred) + minchred = mada; + maxredaut = sqrt(reduc*maxchred); + minredaut = sqrt(reduc*minchred); + + if(!denoiseMethodRgb) + madb = SQR(Mad(WavCoeffs_b[dir], W_ab*H_ab)); + else + madb = SQR(MadRgb(WavCoeffs_b[dir], W_ab*H_ab)); + chblue += madb; + if(madb > maxchblue) + maxchblue = madb; + if(madb < minchblue) + minchblue = madb; + maxblueaut = sqrt(reduc*maxchblue); + minblueaut = sqrt(reduc*minchblue); + + chau += (mada+madb); + nb++; + //here evaluation of automatic + chaut = sqrt(reduc*chau/(nb + nb)); + redaut = sqrt(reduc*chred/nb); + blueaut = sqrt(reduc*chblue/nb); + Nb = nb; + } + +} + + +void ImProcFunctions::WaveletDenoiseAll_info(int levwav, wavelet_decomposition &WaveletCoeffs_a, + wavelet_decomposition &WaveletCoeffs_b, float **noisevarlum, float **noisevarchrom, float **noisevarhue, int width, int height, float noisevar_abr, float noisevar_abb, LabImage * noi, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float &maxblueaut, float &minredaut, float &minblueaut,int schoice, bool autoch, + float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, float &maxchred, float &maxchblue, float &minchred, float &minchblue, int &nb, float &chau, float &chred, float &chblue, bool denoiseMethodRgb, bool multiThread ){ + + int maxlvl = levwav; + for (int lvl=0; lvl TIF and JPG + if(gam <1.9f) + gam=1.f - (1.9f-gam)/3.f;//minimum gamma 0.7 + else if (gam >= 1.9f && gam <= 3.f) + gam=(1.4f/1.1f)*gam - 1.41818f; + } + gamslope = exp(log((double)gamthresh)/gam)/gamthresh; + bool denoiseMethodRgb = (dnparams.dmethod=="RGB"); + if(denoiseMethodRgb) { + for (int i=0; i<65536; i++) { + gamcurve[i] = (Color::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) * 32768.0f; + } + } + else { + for (int i=0; i<65536; i++) { + gamcurve[i] = (Color::gamman((double)i/65535.0,gam)) * 32768.0f; + } + } +} + +void ImProcFunctions::calcautodn_info (float &chaut, float &delta, int Nb, int levaut, float maxmax, float lumema, float chromina, int mode, int lissage, float redyel, float skinc, float nsknc) { + + float reducdelta=1.f; + if (params->dirpyrDenoise.smethod == "shalbi") + reducdelta = (float)settings->nrhigh; + + chaut = (chaut*Nb-maxmax)/(Nb-1);//suppress maximum for chaut calcul + if ((redyel > 5000.f || skinc > 1000.f) && nsknc < 0.4f && chromina > 3000.f) + chaut *= 0.45f;//reduct action in red zone, except skin for high / med chroma + else if ((redyel>12000.f || skinc > 1200.f) && nsknc < 0.3f && chromina > 3000.f) + chaut *= 0.3f; + + if (mode==0 || mode==2) {//Preview or Auto multizone + if (chromina > 10000.f) chaut *= 0.7f;//decrease action for high chroma (visible noise) + else if (chromina > 6000.f) chaut *= 0.9f; + else if (chromina < 3000.f) chaut *= 1.2f;//increase action in low chroma==> 1.2 /==>2.0 ==> curve CC + else if (chromina < 2000.f) chaut *= 1.5f;//increase action in low chroma==> 1.5 / ==>2.7 + + if (lumema < 2500.f) chaut *= 1.3f;//increase action for low light + else if (lumema < 5000.f) chaut *= 1.2f; + else if (lumema > 20000.f) chaut *= 0.9f;//decrease for high light + } else if (mode == 1) {//auto ==> less coefficient because interaction + if (chromina > 10000.f) chaut *= 0.8f;//decrease action for high chroma (visible noise) + else if (chromina > 6000.f) chaut *= 0.9f; + else if (chromina < 3000.f) chaut *= 1.5f;//increase action in low chroma + else if (chromina < 2000.f) chaut *= 2.2f;//increase action in low chroma + if (lumema < 2500.f) chaut *= 1.2f;//increase action for low light + else if (lumema < 5000.f) chaut *= 1.1f; + else if (lumema > 20000.f) chaut *= 0.9f;//decrease for high light + } + + if(levaut==0) {//Low denoise + if(chaut > 300.f) + chaut = 0.714286f*chaut + 85.71428f; + } + + delta = maxmax-chaut; + delta *= reducdelta; + + if (lissage==1 || lissage==2) { + if (chaut < 200.f && delta < 200.f ) delta *= 0.95f; + else if (chaut < 200.f && delta < 400.f ) delta *= 0.5f; + else if (chaut < 200.f && delta >= 400.f ) delta = 200.f; + else if (chaut < 400.f && delta < 400.f ) delta *= 0.4f; + else if (chaut < 400.f && delta >= 400.f ) delta = 120.f; + else if (chaut < 550.f) delta *= 0.15f; + else if (chaut < 650.f) delta *= 0.1f; + else if (chaut >= 650.f) delta *= 0.07f; + if (mode==0 || mode==2) {//Preview or Auto multizone + if (chromina < 6000.f) delta *= 1.4f;//increase maxi + if (lumema < 5000.f) delta *= 1.4f; + } + else if (mode==1) {//Auto + if (chromina < 6000.f) delta *= 1.2f;//increase maxi + if (lumema < 5000.f) delta *= 1.2f; + } + } + if (lissage==0) { + if (chaut < 200.f && delta < 200.f ) delta *= 0.95f; + else if (chaut < 200.f && delta < 400.f ) delta *= 0.7f; + else if (chaut < 200.f && delta >= 400.f ) delta = 280.f; + else if (chaut < 400.f && delta < 400.f ) delta *= 0.6f; + else if (chaut < 400.f && delta >= 400.f ) delta = 200.f; + else if (chaut < 550.f) delta *= 0.3f; + else if (chaut < 650.f) delta *= 0.2f; + else if (chaut >= 650.f) delta *= 0.15f; + if (mode==0 || mode==2) {//Preview or Auto multizone + if (chromina < 6000.f) delta *= 1.4f;//increase maxi + if (lumema < 5000.f) delta *= 1.4f; + } + else if (mode==1) {//Auto + if (chromina < 6000.f) delta *= 1.2f;//increase maxi + if (lumema < 5000.f) delta *= 1.2f; + } + } + +} + +SSEFUNCTION void ImProcFunctions::RGB_denoise_info(Imagefloat * src, Imagefloat * provicalc, const bool isRAW, LUTf &gamcurve, float gam, float gamthresh, float gamslope, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float &maxblueaut, float &minredaut, float &minblueaut, float &nresi, float &highresi, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, bool multiThread) +{ + if ((settings->leveldnautsimpl==1 && dnparams.Cmethod == "MAN") || (settings->leveldnautsimpl==0 && dnparams.C2method == "MANU")) { + //nothing to do + return; + } + + int hei,wid; + float** lumcalc; + float** acalc; + float** bcalc; + hei=provicalc->height; + wid=provicalc->width; + TMatrix wprofi = iccStore->workingSpaceMatrix (params->icm.working); + + const float wpi[3][3] = { + {static_cast(wprofi[0][0]),static_cast(wprofi[0][1]),static_cast(wprofi[0][2])}, + {static_cast(wprofi[1][0]),static_cast(wprofi[1][1]),static_cast(wprofi[1][2])}, + {static_cast(wprofi[2][0]),static_cast(wprofi[2][1]),static_cast(wprofi[2][2])} + }; + + lumcalc = new float*[hei]; + for (int i=0; ir(ii,jj); + float GL = provicalc->g(ii,jj); + float BL = provicalc->b(ii,jj); + // determine luminance for noisecurve + float XL,YL,ZL; + Color::rgbxyz(RL,GL,BL,XL,YL,ZL,wpi); + Color::XYZ2Lab(XL, YL, ZL, LLum, AAum, BBum); + lumcalc[ii][jj]=LLum; + acalc[ii][jj]=AAum; + bcalc[ii][jj]=BBum; + } + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + const int imheight=src->height, imwidth=src->width; + + bool denoiseMethodRgb = (dnparams.dmethod == "RGB"); + + const float gain = pow (2.0f, float(expcomp)); + + int tilesize; + int overlap; + if(settings->leveldnti == 0) { + tilesize = 1024; + overlap = 128; + } + if(settings->leveldnti == 1) { + tilesize = 768; + overlap = 96; + } + + int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; + + //always no Tiles + int kall=0; + Tile_calc (tilesize, overlap, kall, imwidth, imheight, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); + const float wp[3][3] = { + {static_cast(wprof[0][0]),static_cast(wprof[0][1]),static_cast(wprof[0][2])}, + {static_cast(wprof[1][0]),static_cast(wprof[1][1]),static_cast(wprof[1][2])}, + {static_cast(wprof[2][0]),static_cast(wprof[2][1]),static_cast(wprof[2][2])} + }; + + float chau=0.f; + float chred=0.f; + float chblue=0.f; + float maxchred=0.f; + float maxchblue=0.f; + float minchred =100000000.f; + float minchblue=100000000.f; + int nb=0; + int comptlevel=0; + + // To avoid branches in loops we access the gammatabs by pointers + LUTf *denoiseigamtab; + switch(settings->denoiselabgamma) { + case 0: denoiseigamtab = &(Color::igammatab_26_11); + break; + case 1: denoiseigamtab = &(Color::igammatab_4); + break; + default: denoiseigamtab = &(Color::igammatab_55); + break; + } + + + for (int tiletop=0; tiletop 0.) + intermred = (dnparams.redchro/10.); + else + intermred = (float) dnparams.redchro/7.0;//increase slower than linear for more sensit + if(dnparams.bluechro > 0.) + intermblue =(dnparams.bluechro/10.); + else + intermblue = (float) dnparams.bluechro/7.0;//increase slower than linear for more sensit + realred = interm_med + intermred; + if (realred < 0.f) + realred = 0.001f; + realblue = interm_med + intermblue; + if (realblue < 0.f) + realblue = 0.001f; + //TODO: implement using AlignedBufferMP + //fill tile from image; convert RGB to "luma/chroma" + + if (isRAW) {//image is raw; use channel differences for chroma channels +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for if(multiThread) +#endif + for (int i=tiletop; i>1][j>>1]); + bNv = LVFU(bcalc[i>>1][j>>1]); + _mm_storeu_ps(&noisevarhue[i1>>1][j1>>1], xatan2f(bNv,aNv)); + _mm_storeu_ps(&noisevarchrom[i1>>1][j1>>1], _mm_max_ps(c100v,_mm_sqrt_ps(SQRV(aNv)+SQRV(bNv)))); + } + for (; j>1][j>>1]; + float bN = bcalc[i>>1][j>>1]; + float cN = sqrtf(SQR(aN)+SQR(bN)); + noisevarhue[i1>>1][j1>>1] = xatan2f(bN,aN); + if(cN < 100.f) + cN=100.f;//avoid divided by zero + noisevarchrom[i1>>1][j1>>1] = cN; + } +#else + for (int j=tileleft; j>1][j>>1]; + float bN = bcalc[i>>1][j>>1]; + float cN = sqrtf(SQR(aN)+SQR(bN)); + float hN = xatan2f(bN,aN); + if(cN < 100.f) + cN = 100.f;//avoid divided by zero + noisevarchrom[i1>>1][j1>>1] = cN; + noisevarhue[i1>>1][j1>>1] = hN; + } +#endif + } +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for if(multiThread) +#endif + for (int i=tiletop; i>1][j>>1]; + Llum = Llum < 2.f ? 2.f : Llum; //avoid divided by zero ? + Llum = Llum > 32768.f ? 32768.f : Llum; // not strictly necessary + noisevarlum[i1>>1][j1>>1]= Llum; + } + } + if (!denoiseMethodRgb){//lab mode, modification Jacques feb 2013 and july 2014 + +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for if(multiThread) +#endif + for (int i=tiletop; ir(i,j); + float G_ = gain*src->g(i,j); + float B_ = gain*src->b(i,j); + + R_ = (*denoiseigamtab)[R_]; + G_ = (*denoiseigamtab)[G_]; + B_ = (*denoiseigamtab)[B_]; + + //apply gamma noise standard (slider) + R_ = R_<65535.0f ? gamcurve[R_] : (Color::gamman((double)R_/65535.0, gam)*32768.0f); + G_ = G_<65535.0f ? gamcurve[G_] : (Color::gamman((double)G_/65535.0, gam)*32768.0f); + B_ = B_<65535.0f ? gamcurve[B_] : (Color::gamman((double)B_/65535.0, gam)*32768.0f); + //true conversion xyz=>Lab + float X,Y,Z; + Color::rgbxyz(R_,G_,B_,X,Y,Z,wp); + + //convert to Lab + float L,a,b; + Color::XYZ2Lab(X, Y, Z, L, a, b); + + labdn->a[i1][j1] = a; + labdn->b[i1][j1] = b; + } + } + } + else {//RGB mode + + for (int i=tiletop/*, i1=0*/; ir(i,j); + float Y = gain*src->g(i,j); + float Z = gain*src->b(i,j); + + X = X<65535.0f ? gamcurve[X] : (Color::gamma((double)X/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + Y = Y<65535.0f ? gamcurve[Y] : (Color::gamma((double)Y/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + Z = Z<65535.0f ? gamcurve[Z] : (Color::gamma((double)Z/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + + labdn->a[i1][j1] = (X-Y); + labdn->b[i1][j1] = (Y-Z); + } + } + } + + } else {//image is not raw; use Lab parametrization + for (int i=tiletop/*, i1=0*/; ir(i,j) ;//for luminance denoise curve + float gLum=src->g(i,j) ; + float bLum=src->b(i,j) ; + + //use gamma sRGB, not good if TIF (JPG) Output profil not with gamma sRGB (eg : gamma =1.0, or 1.8...) + //very difficult to solve ! + // solution ==> save TIF with gamma sRGB and re open + float rtmp = Color::igammatab_srgb[ src->r(i,j) ]; + float gtmp = Color::igammatab_srgb[ src->g(i,j) ]; + float btmp = Color::igammatab_srgb[ src->b(i,j) ]; + //modification Jacques feb 2013 + // gamma slider different from raw + rtmp = rtmp<65535.0f ? gamcurve[rtmp] : (Color::gamman((double)rtmp/65535.0, gam)*32768.0f); + gtmp = gtmp<65535.0f ? gamcurve[gtmp] : (Color::gamman((double)gtmp/65535.0, gam)*32768.0f); + btmp = btmp<65535.0f ? gamcurve[btmp] : (Color::gamman((double)btmp/65535.0, gam)*32768.0f); + + float X,Y,Z; + Color::rgbxyz(rtmp,gtmp,btmp,X,Y,Z,wp); + + //convert Lab + Color::XYZ2Lab(X, Y, Z, L, a, b); + + if(((i1|j1)&1) == 0) { + float Llum,alum,blum; + float XL,YL,ZL; + Color::rgbxyz(rLum,gLum,bLum,XL,YL,ZL,wp); + Color::XYZ2Lab(XL, YL, ZL, Llum, alum, blum); + float kN=Llum; + if(kN<2.f) kN=2.f; + if(kN>32768.f) kN=32768.f; + noisevarlum[i1>>1][j1>>1]=kN; + float aN=alum; + float bN=blum; + float hN=xatan2f(bN,aN); + float cN=sqrt(SQR(aN)+SQR(bN)); + if(cN < 100.f) cN=100.f;//avoid divided by zero + noisevarchrom[i1>>1][j1>>1]=cN; + noisevarhue[i1>>1][j1>>1]=hN; + } + labdn->a[i1][j1] = a; + labdn->b[i1][j1] = b; + } + } + } + int datalen = labdn->W * labdn->H; + + //now perform basic wavelet denoise + //last two arguments of wavelet decomposition are max number of wavelet decomposition levels; + //and whether to subsample the image after wavelet filtering. Subsampling is coded as + //binary 1 or 0 for each level, eg subsampling = 0 means no subsampling, 1 means subsample + //the first level only, 7 means subsample the first three levels, etc. + noisevarab_r = SQR(realred) + 0.01f; + noisevarab_b = SQR(realblue) + 0.01f; + + wavelet_decomposition* adecomp; + wavelet_decomposition* bdecomp; + + int schoice = 0;//shrink method + if (dnparams.smethod == "shalbi") + schoice=2; + + const int levwav=5; +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel sections if(multiThread) +#endif +{ +#ifdef _RT_NESTED_OPENMP +#pragma omp section +#endif +{ + adecomp = new wavelet_decomposition (labdn->data+datalen, labdn->W, labdn->H, levwav, 1 ); +} +#ifdef _RT_NESTED_OPENMP +#pragma omp section +#endif +{ + bdecomp = new wavelet_decomposition (labdn->data+2*datalen, labdn->W, labdn->H, levwav, 1 ); +} +} + bool autoch = dnparams.autochroma; + if(comptlevel==0) WaveletDenoiseAll_info(levwav, *adecomp, *bdecomp, noisevarlum, noisevarchrom, noisevarhue, width, height, noisevarab_r, noisevarab_b, labdn, chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, schoice, autoch, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc,maxchred, maxchblue, minchred, minchblue, nb,chau ,chred, chblue, denoiseMethodRgb, multiThread);//enhance mode + comptlevel+=1; + float chresid,chmaxredresid,chmaxblueresid; + nresi=chresid; + highresi=chresid + 0.66f*(max(chmaxredresid,chmaxblueresid) - chresid);//evaluate sigma + delete adecomp; + delete bdecomp; + delete labdn; + for (int i=0; i<(height+1)/2; i++) + delete [] noisevarlum[i]; + delete [] noisevarlum; + for (int i=0; i<(height+1)/2; i++) + delete [] noisevarchrom[i]; + delete [] noisevarchrom; + for (int i=0; i<(height+1)/2; i++) + delete [] noisevarhue[i]; + delete [] noisevarhue; + + }//end of tile row + }//end of tile loop + + for (int i=0; isetProgressStr (Glib::ustring::compose(M("TP_RAW_DMETHOD_PROGRESSBAR"), RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze])); plistener->setProgress (0.0); @@ -201,10 +201,10 @@ SSEFUNCTION void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, // Main algorithm: Tile loop //#pragma omp parallel for shared(rawData,height,width,red,green,blue) private(top,left) schedule(dynamic) - //code is openmp ready; just have to pull local tile variable declarations inside the tile loop - -// Issue 1676 -// use collapse(2) to collapse the 2 loops to one large loop, so there is better scaling + //code is openmp ready; just have to pull local tile variable declarations inside the tile loop + +// Issue 1676 +// use collapse(2) to collapse the 2 loops to one large loop, so there is better scaling #pragma omp for schedule(dynamic) collapse(2) nowait for (top=winy-16; top < winy+height; top += TS-32) for (left=winx-16; left < winx+width; left += TS-32) { diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 16a3b27e8..ffd31cdf5 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1,1607 +1,1607 @@ -/* - - DO NOT EDIT THIS FILE! - - All changes made here will be lost on software update. - If you want to add custom values or changes existing ones, - create a "camconst.json" file next to your personal "options" file. - Its values will then override and/or complete the ones of this file. - - If you add values for your own camera and are okay to share them with - RawTherapee's community, please drop a link on the user's forum - - IMPORTANT: - ---------- - - 1. If you set the dcraw matrix in your user file for an already existing entry - in RT's file (same camera, same model), your values will replace RT's ones. - 2. If you set the Black level(s) values in your user file for an already existing - entry in RT's file, your values will replace RT's ones, even if RT's ones are - more complete and/or detailed. You might want to copy/paste RT's levels first - (if provided) to your user's file and complete/modify it. - - Same for the White level(s), independently from the Black level(s). - - ----------------------------------------------------------------------------------- - - -This file is in JSON format and contains camera constants which RawTherapee uses -when parsing raw files. - -Raw files themselves unfortunately do not contain all information needed for making -a raw conversion, typically color response information and black/white levels are -missing. That's why this file is needed. - -It's read once during startup, so if the file is updated you need to restart -RawTherapee in order to take effect. The file is not intended for modification by -the casual user, but advanced users can add missing camera information to this file. -If you do so please report at http://code.google.com/p/rawtherapee/issues so we can -extend the distributed version of this file so your provided camera information -becomes available to all. - -RawTherapee uses DCRAW as the raw format parser. DCRAW contains hard-coded camera -constants, but not for all cameras and not always accurate information. For example -DCRAW only support one white level, while some cameras have different white levels -per channel and per ISO. If a camera is not listed in this file the constants from -DCRAW will be used, if listed here this information will override any constants in -DCRAW (if any). - -Some cameras may only have partial information here, for example if the raw file -itself contains a color matrix it's not entered here. A camera whose black level -is measured on special pixels in the raw file should only have white levels here -etc. - -Examples: - - { - // make and model separated with single space, must match make - // and model as provided by dcraw (case-insensitive). - "make_model": "ManufacturerA ModelB", - // ColorMatrix with D65 Calibration Illuminant, in dcraw format - "dcraw_matrix": [ 7530, -1942, -255, -4318, 11390, 3362, -926, 1694, 7649 ], - // black level (or black offset if a base black is already extracted from exif by Dcraw, see Panasonic, resent Nikon ) - // and white level same for all colors at all ISOs - "ranges": { "black": 10, "white": 1000 }, - // crop away masked sensor borders, 10 pixels left, 20 pixels top, resulting image width/height 4000x3000 - // instead of width/height you can write a negative number which specifies how much of right/bottom border - that should be removed but keep in mind that sometimes after converting to DNG the borders are already - cropped so the "negative number" way is not totally safe. - "raw_crop": [ 10, 20, 4000, 3000 ], - // Almost same as MaskedAreas DNG tag, used for black level measuring here two areas defined - "masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ], - The difference here is the meaning of the numbers which here are expressing the absolute distance (in pixels) - of each side of each rectangular "masked area" from the top and left side of the sensor - - the first number is the distance of the top edge from the sensor's top - - the second is the distance of the left side from the sensor's left - - the third is the distance of the bottom side from the sensor's top - - the fourth is the distance of the right side from the sensor's left - }, - - { - "make_model": "ManufacturerA ModelB", - "dcraw_matrix": [ 7530,-1942,-255,-4318,11390,3362,-926,1694,7649 ], - // black and white levels per ISO per channel - // this example only two ISOs, normally the list should be more populated. - // When RawTherapee asks for black/white levels for a specific ISO the closest - // match is picked. - "ranges": { - "black": [ - { "iso": 100, "levels": 10 }, // here only one level, same level for all channels - { "iso": 3200, "levels": [ 50, 60, 50 ] } // 3 levels, G2 same as G1 - ], - "white": [ - { "iso": 100, "levels": [ 10000, 11000, 10000, 12000 ] }, // 4 levels, G1 and G2 different - { "iso": 3200, "levels": [ 11000, 11000, 10000, 12000 ] } - ] - } - } - -How to measure white levels: ----------------------------- - -Dcraw which provides the default values to RawTherapee often provides too high -white levels, and only provides a single value regardless of color channel, ISO -or aperture. If you open an image with a large clipped area and that is -rendered in a pink/magenta color rather than white it usually means that the -white level constant is too high. You can fix this by adjusting the -"Raw White Point" in the raw tab inside RawTherapee, or permanently fix it by -measuring and providing a more exact white level in camconst.json so -RawTherapee gets to know from start where the camera actually clips. - -Providing a complete and detailed white-level profile can be a quite large -and complicated effort. As an alternative you can provide a simpler profile. -We suggest one of the following alternatives in rising difficulty (and -generally diminishing return): - -A) Provide a single white-level value measured on the native ISO (base ISO). - For many cameras this will actually be complete information, those that - don't vary on channel, ISO or aperture. -B) Check through all ISOs and if there are differences in white level provide - an array with white level per ISO. -C) In addition to ISO, check for aperture scaling and add that. -D) In addition to ISO and aperture scaling check for color channel - differences and add that. - -Doing A) is often better than nothing, as dcraw's default is often too high. -B) can also be worthwhile for some cameras (or else you'll get pink highlights -for some ISOs), while C) and D) can generally be seen as fine-tuning. - -Here follows a guide how to measure white levels (clipping levels): - -Shoot with your camera into a bright light source, such as a lamp, and make -sure the shutter speed is long enough to get overexposure (we want -clipping!). Preferably overexpose lightly, say 1 or 2 stops if you can. The -reason for this is that some cameras with fuzzy white levels may look less -fuzzy than they actually are if over-exposure is heavy. - -Use f/5.6 or smaller aperture (=larger f-number) to avoid any raw scaling -the camera might have for large apertures. - -Open the file in a raw analyzer such as Rawdigger and check the pixel values -for the clipped areas (if you are using Rawdigger, make sure you have disabled -"subtract black" in preferences or else sample values can be wrong). In this -stage we always look at white level before black level subtraction! White -levels can be different on color channel (R, G1, B, G2, note the two greens, -most often both green channels have the same white level though) and vary -depending on ISO setting, so if you want to provide a complete profile make -one shoot for each ISO (even 1/3 steps, so yes it can be quite a lot of -pictures to shoot and check). - -In addition, many cameras scale the raw values for large apertures. It's -generally not that important to cover this, but if you want to extract most -out of the camera you should cover this too. Then you need to shoot with a -wide aperture lens (ideally the widest available from the manufacturer) and -test each aperture (1/3 steps) from the widest (say f/1.2) until the camera -stops scaling the raw values (usually f/2.8 or f/4.0). If the camera also -have ISO scaling you need to shoot at these different ISOs to detect any -differences in scaling, there can be a bit of variation. If you don't have -access to the widest lens available for the system (say only an f/1.8 lens -instead of an f/1.2) it can still be valuable to have the values down to -what you can provide. Brands known to have models that have aperture scaling -of white levels include Canon and Nikon. Note that if white levels are not -scaled the camera may have raw scaling anyway (Sony for example), but as -such scaling will not affect raw decoding we don't need to care about that. - -PROVIDE CONSERVATIVE VALUES. Most cameras have a little noise at the white -level, and some can have a lot. In your raw analyzer, move around and look at -the values in the clipped areas to get a sense of the variation, and/or look -at the histogram. While it's common to with very little variation, say only -+/-2 units, some can have +/-500 or more (some may have different variation -depending on ISO). There can also be camera-to-camera variation. - -If the white level is set too high RawTherapee will not think the pixels are -clipped and you can get discoloured highlights (usually pink), this is what -we want to avoid. If white level is set too low RawTherapee will clip early, ie -you lose a little highlight detail, but the color is rendered correctly and -highlight reconstruction can work properly, so this is not as bad. This is why -we want conservative values. - -By conservative values we mean that if you see a white level of most often -15760 and occassionally 15759 (ie very small variation of white level which -is a common case), you set the white level around 40-80 14bit units below or -10-20 12bit units. Say at 15700 in this example, or 4080 instead of 4095 for -12bit raws. This way we get a little margin from noise and camera variation. -Since sensor raw values are linear you lose in this example log2(1-50/15760) = --0.005 stop of detail, ie irrelevant. Thus it's better to provide RawTherapee -with knowledge where the image clips rather than keeping that last 0.005 stop -of highlight information and risking that clipping will not be detected -properly. - -It is very usual for white level to be a bell distribution instead of a candle -when the camera applies long exposure noise reduction by subtracting a black frame -and/or when the system is destabilized due to temperature. Some models have -always a bell distribution at WL. -If you have a fuzzy white level look at the linear histogram; you will probably -see a normal/gaussian distribution (bell shape) noise peak at clipping and -probably also a peak at a hard raw data clip level usually at or close to a -power of two - 1, such as 4095 or 16383. Then you pick a value just before the -bell shape rises, ie to the left of the bell meaning that you cut away the -whole fuzzy noise peak. If a little of the starting edge of the noise will be -included it's not harmful, but 99% of it should be above. -This would mean that it's better to measure white level on long exposure/ high temp -raws but since this if difficult and time consuming we choose to measure on normal -raws and cover the abnormalities whith the conservative WL values. - -If you have used Adobe's DNG Converter and analyzed it's output you may have -noticed that it's very conservative regarding white levels, ie it cuts away -quite a lot from the top. While we also recommend to be conservative, you can -generally be a little bit less so than Adobe's DNG Converter. RawTherapee is -meant to max out what you can get from your camera, and the white levels should -mirror that, within reason. - -The aperture scaling feature is meant to raise the white level to not miss out -on highlight detail when the camera has scaled the raw values (and thus -raised white levels). Many cameras do this, but not all, and can only do it -for lenses that report aperture to the camera (ie you see it in the EXIF -data). Providing proper aperture scaling values is a bit more advanced task, -so if you are unsure we recommend to skip that part. - -Beware that the raw format may have a ceiling so that it clips scaled values, -for example the Canon 5D mark II maxes out at 16383 which happens at f/1.8 -for ISOs with the white level at 15750, but for ISO160 when the white level -is 12800 it does not max out. If there is such a raw limit it must also be -provided ("ranges":"white_max"). Usually you will not need a margin on -white_max as it clips there as a result of an in-camera math operation. - -Note that aperture scaling can be quite small, for the 5D mark II it's only -0.2 stop down to f/1.2 and then it can be discussed if it's worthwhile to care. -The "worst" cameras scale about 0.6 stops though, and then it's more -valuable to compensate. If you skip aperture scaling RawTherapee will clip the -files a little bit too early and you miss that last fraction of highlight -detail, but you get no processing problems. Setting unconservative scale -factors can on the other hand cause a too high whitelevel and break highlight -processing, so be careful. - -Scaling can vary sligthly depending on ISO (if white levels vary) so make -sure to provide conservative scalings so regardless of ISO you don't get a -too high white level. We recommend to keep a small margin here also -white levels, ie 0.5% lower or so. For example if base (not conservative!) -white level is 15750 and the scaled is 16221 we have a scaling factor of -16221/15750=1.0299 ie +2.9% we set the factor to 1.025 to keep a margin. -The abnormal cases are already covered by setting conservative per ISO White levels. - -The scale factor you provide here is applied on the white level before black -level subtraction (if any), ie directly on the white level value you provide in -the camconst.json file. Black level (if provided) is not scaled. Please report -to us if you come across a camera which scales black levels, then we can add -that as an option. Usually the camera applies an offset to shift back the -black level to the standard level after scaling. - -If RawTherapee doesn't find an entry for the aperture used in the image, it -will pick the closest above. Ie if the apertures 1.0 and 2.0 is in the table -and the image has aperture 1.2, it will pick scaling for 2.0, even if 1.0 is -the closer aperture. The reason for always checking the closest above is that -we rather get a bit too low white level than too high, as discussed before. - -Some cameras have different white levels on different color channels. When -this is the case the difference is often so small so you can just provide a -single value instead, ie a conservative value based on the lowest clipping. - -What we know at the time of writing about different brands/models (not -complete info): - - - Canon CR2: typically same clipping per channel, but significant variations - on ISO and aperture. Maxes out at 16383, black level measured on masked - black pixels, ie don't provide that. - - Nikon NEF: sometimes different clipping per color (most often negligible - though). Will do aperture and ISO scaling, but often to a lesser extent - than Canon files, ie not as much to gain. - - Sony ARW2: no scaling. Generally black level around 512, and white level - 16350 and to be conservative say 16300. - -Note that some raw formats may go through a certain amount of pre-processing -based on meta data, such as curve and levels adjustments and various -calibrations. The Phase One IIQ is one example, and this means that if you -look at the data in a raw analyzer such as RawDigger it may perform a -different type of preprocessing than RawTherapee's loader does, and you may -end up providing incompatible black/white levels. - -You can use RawTherapee for analysis too, it's safer as you are using it's -own raw decoder but it's not as user-friendly: enable verbose mode in options -so you get output on the console. When you load a file you will see a message -of current black and white levels and if they came from dcraw or camconst.json. -If you're adjusting an existing camconst.json value you can just read what it is in -the file and not need to enable verbose output. - -Reset exposure sliders to neutral, and zoom in on a large clipped highlight. -Move around the mouse pointer within, it should show stable 100% on R G B. If -so, the white level is not too high, it could however be too low. To test that, -go to the raw tab and adjust the "whitepoint linear correction factor", reduce -it until one of the channels is no longer 100%, and then increase in steps of -0.01 until all are 100 again. Usually you play around in the range 0.90 to -0.99, ie a very small adjustment. When you've found this factor you should -apply it on the old white level to find a new larger one. As RT's "whitepoint -linear correction factor" work after blacklevel subtraction and camconst.json -want values without it we need to do some math: - -BL = black level (typically something near 0, 256, 512, 1024 or 2048 find it in the - verbose output or if available in camconst.json) -F = whitepoint linear correction factor you just found out (typically in the - range 0.90 to 0.99 if you need to increase white level, 1.01 to 1.10 if - decrease) -oldWL = old white level, found in verbose output or in camconst.json if - available. - -new white level = BL + (oldWL - BL) / F - -Note that if black level is 0 which it is for many cameras, the formula -simplifies to: new white level = oldWL / F. - -Here's an example from a Canon 1000D: black level is 256, old white level is -3651, whitepoint correction factor becomes 0.90, then new white level is -256 + (3651 - 256) / 0.9 = 4028. - -If your camera have different black levels per channel use the one which -yields the smallest white level (can be the largest or smallest, test!). - -This new white level you then enter in your camconst.json file. The same -procedure can be used if the white level is too high, ie if you see pink -highlights, then increase the correction factor above 1.0 until you just start -seeing stable 100% on all channels, you use the same formula to calculate the -new smaller white level. - -About black levels: -------------------- - -Unlike for white levels it's much more common that black levels can be -derived from the format. Either it's simply 0 (typical for old Nikon cameras, -newer Nikons (year2013-14) have a BL at around 150 12bit or 600/768 14bit ), -or it can be derived from masked pixels (typical for Canon cameras) or otherwise -be extracted from some tag. -Some formats have built-in subtraction information and are pre-processed by DCRaw -to end up at a black level of zero(Phase One's IIQ). -For Panasonic raws beginning from Dcraw v9.21 Dcraw/RT reads base BL from exif data -(tags 0x001c BlackLevelRed, 0x001d BlackLevelGreen, 0x001e BlackLevelBlue)and we -define in "ranges": { "black": the needed offset of around 15. The (total) BL RT displays is base+offset -In all, you typically should not care about the black level in camconst.json, -any information that can be derived from the raw file itself should not be specified in camconst.json! -Sony's ARW2 is one of the few exceptions (with single black level around 512, or 800 for RX10/100 models), -but DCraw generally has good constants for these already. - -Currently we have chosen not to provide any guide how to measure black levels -as we don't think it will be a common task (it's also more difficult to do -than measure white levels). If you experience a black level issue it's more -likely due to a format parsing bug which should be fixed in DCRaw and/or -RawTherapee's raw format parser. - -How does a black level issue look? If the image has a color cast and is -possibly duller than normal it's likely that black levels are off. The color -cast is typically stronger in darker colors but it can be hard to see, it's -more often experienced as a cast over the whole image. - -*/ -{"camera_constants": [ - -/* - -When adding camera constants please set a quality level so we know the status for future updates - -Quality A: complete information, no need to add more, to the best of our knowledge -Quality B: not complete, but very little to gain from adding more -Quality C: complementing with additional information would provide significant gain -Quality X: unknown, ie we knowing to little about the camera properties to know if - we have enough info or not. - -*/ - - { // quality A - "make_model": "Canon EOS 5D Mark II", - "dcraw_matrix": [ 4716,603,-830,-7798,15474,2480,-1496,1937,6651 ], - "ranges": { - // black levels are read from raw masked pixels - // white levels are same for all colors, but vary on ISO - "white": [ - { "iso": 50, "levels": 15600 }, // typical: 15760 - { "iso": 100, "levels": 15600 }, - { "iso": 125, "levels": 15600 }, - { "iso": 160, "levels": 12700 }, - { "iso": 200, "levels": 15600 }, - { "iso": 250, "levels": 15600 }, - { "iso": 320, "levels": 12700 }, // typical: 12810 - { "iso": 400, "levels": 15600 }, - { "iso": 500, "levels": 15600 }, - { "iso": 640, "levels": 12700 }, - { "iso": 800, "levels": 15600 }, - { "iso": 1000, "levels": 15600 }, - { "iso": 1250, "levels": 12700 }, - { "iso": 1600, "levels": 15600 }, - { "iso": 2000, "levels": 15600 }, - { "iso": 2500, "levels": 15600 }, - { "iso": 3200, "levels": 15600 }, - { "iso": 4000, "levels": 15600 }, - { "iso": 5000, "levels": 15600 }, - { "iso": 6400, "levels": 16200 }, // typical: 16383 - { "iso": 12800, "levels": 16200 }, - { "iso": 25600, "levels": 16200 } - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for and f/1.0 (had no lenses to test with), but the - typical 15700 white level maxes out at "white_max" for f/1.8 and below anyway. */ - { "aperture": 1.2, "scale_factor": 1.100 }, // guessed by relative 5DIII data - { "aperture": 1.4, "scale_factor": 1.077 }, - { "aperture": 1.6, "scale_factor": 1.054 }, - { "aperture": 1.8, "scale_factor": 1.039 }, - { "aperture": 2.0, "scale_factor": 1.031 }, - { "aperture": 2.2, "scale_factor": 1.021 }, - { "aperture": 2.5, "scale_factor": 1.016 }, - { "aperture": 2.8, "scale_factor": 1.010 }, - { "aperture": 3.2, "scale_factor": 1.004 }, - { "aperture": 3.5, "scale_factor": 1.003 } - ] - } - }, - { // quality A, - "make_model": "Canon EOS 5D Mark III", - "dcraw_matrix": [ 6722,-635,-963,-4287,12460,2028,-908,2162,5668 ], - "ranges": { - // black levels are read from raw masked pixels - // white levels are same for all colors, but vary on ISO - "white": [ - { "iso": [ 50, 100, 125, 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000, 12800, 16000, 20000 ], "levels": 15180 }, // typical: 15282 - { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000 ], "levels": 13200 }, // typical: 13306 - { "iso": [ 25600, 32000, 40000, 51200, 102400 ], "levels": 16200 } - ], - "white_max": 16383, - "aperture_scaling": [ - { "aperture": 1.2, "scale_factor": 1.130 }, - { "aperture": 1.4, "scale_factor": 1.090 }, - { "aperture": 1.6, "scale_factor": 1.065 }, - { "aperture": 1.8, "scale_factor": 1.040 }, - { "aperture": 2.0, "scale_factor": 1.025 }, - { "aperture": 2.2, "scale_factor": 1.020 }, - { "aperture": 2.5, "scale_factor": 1.015 }, - { "aperture": 2.8, "scale_factor": 1.010 }, - { "aperture": 3.2, "scale_factor": 1.005 }, - { "aperture": 3.5, "scale_factor": 1.002 } - ] - } - }, - - { // Quality C, intermediate ISO samples missing but safely guessed, aperture scaling measures missing - "make_model": [ "Canon EOS 5DS R", "Canon EOS 5DS" ], - // "dcraw_matrix": [ 6848,-1661,-221,-3904,10931,3434,-470,1251,6039 ], // DNG_V9.0 A - "dcraw_matrix": [ 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 ], // DNG_V9.0 D65 - "raw_crop": [ 192, 96, 8696, 5800 ], // 800, 300, 7500, 4700 - 160,64,8730x5800 - sensor 8896x5920 top64, left160, official crop left196, top100, right 8883, bottom 5891, 8688X5792 - "masked_areas": [ 100, 40, 5892, 158 ], // left out 40 first columns from calculations because possibly the BL is still imbalanced there - "ranges": { - "white": [ - { "iso": 100, "levels": 14650 }, // typical 14733 - { "iso": [ 160, 320, 640, 1250, 2500, 5000 ], "levels": 15280 }, // typical 15383 - { "iso": [ 125, 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200 ], "levels": 15280 }, // typical 15383 - { "iso": [ 4000, 6400, 8000, 10000, 12800, 16000, 20000, 25600 ], "levels": 15100 } // clippings at R 15200-15280, G1,G2,B 15360-15390 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: scale factors measured for f/2.8 only, */ - { "aperture": 1.4, "scale_factor": 1.055 }, // guessed - { "aperture": 1.6, "scale_factor": 1.034 }, // guessed - { "aperture": 1.8, "scale_factor": 1.021 }, // guessed - { "aperture": 2.0, "scale_factor": 1.013 }, // guessed - { "aperture": 2.2, "scale_factor": 1.008 }, // guessed - { "aperture": 2.5, "scale_factor": 1.005 }, // guessed - { "aperture": 2.8, "scale_factor": 1.003 }, // 14783/14733 - { "aperture": 3.2, "scale_factor": 1.000 }, // guessed - { "aperture": 3.5, "scale_factor": 1.000 } - ] - } - }, - - { // Quality A, some missing scaling factors are safelly guessed - most samples by sfink16 at RT forums - "make_model": "Canon EOS 6D", - "dcraw_matrix": [ 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 ], - "ranges": { - "white": [ - { "iso": [ 50, 100, 125, 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000, 12800, 16000, 25600 ], "levels": 15180 }, // typical 15283 - { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000, 20000 ], "levels": 13100 }, // typical 13225 - { "iso": [ 51200, 102400 ], "levels": 16280 } // typical 16383 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.0 (had no lenses to test with), but the - ISO 160-320... 12650 white levels maxes out at "white_max" for f/1.2 and below anyway. */ - { "aperture": 1.2, "scale_factor": 1.130 }, // from histogramm 1 gap in every 7 levels - { "aperture": 1.4, "scale_factor": 1.090 }, // histogram 3 gaps in every 32 levels - { "aperture": 1.6, "scale_factor": 1.060 }, // 16213/15283 - { "aperture": 1.8, "scale_factor": 1.040 }, // guessed - { "aperture": 2.0, "scale_factor": 1.030 }, // 15800/15283 - { "aperture": 2.2, "scale_factor": 1.020 }, // guessed - { "aperture": 2.5, "scale_factor": 1.015 }, // 15541/15283 - { "aperture": 2.8, "scale_factor": 1.010 }, // 15437/15283 - { "aperture": 3.2, "scale_factor": 1.005 }, // 15361/15283 - { "aperture": 3.5, "scale_factor": 1.000 } // no sample - ] - } - }, - { // Quality A, ISO and aperture WL data by CharlyW at RawTherapee forums, missing samples safely guessed - "make_model": "Canon EOS 7D", - "dcraw_matrix": [ 5962,-171,-732,-4189,12307,2099,-911,1981,6304 ], // Colin Walker - // "dcraw_matrix": [ 6844,-996,-856,-3876,11761,2396,-593,1772,6198 ], // dcraw - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13584 - { "iso": [ 160, 320, 640, 1250, 2500 ], "levels": 12550 }, // typical 12650 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 5000, 6400, 12800 ], "levels": 15200 } // typical 15304 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (no lenses to test with), but the - typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.250 }, // guessed - { "aperture": 1.6, "scale_factor": 1.150 }, // guessed - { "aperture": 1.8, "scale_factor": 1.110 }, // 15196/13584 - { "aperture": 2.0, "scale_factor": 1.080 }, // 14734/13584 - { "aperture": 2.2, "scale_factor": 1.050 }, // 14386/13584 - { "aperture": 2.5, "scale_factor": 1.040 }, // 14272/13584 - { "aperture": 2.8, "scale_factor": 1.030 }, // 14042/13584 - { "aperture": 3.2, "scale_factor": 1.015 }, // guessed - { "aperture": 3.5, "scale_factor": 1.000 } // guessed negligible - ] - } - }, - - { // Quality b, ISO and aperture WL data by ..... at RawTherapee forums, missing samples safely guessed - "make_model": "Canon EOS 550D", - "dcraw_matrix": [ 6941,-1164,-857,-3825,11597,2534,-416,1540,6039 ], // dcraw 550d - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13584 - { "iso": [ 160, 320, 640, 1250, 2500 ], "levels": 12550 }, // typical 12650 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 5000, 6400, 12800 ], "levels": 15200 } // typical 15304 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (no lenses to test with), but the - typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.250 }, // guessed - { "aperture": 1.6, "scale_factor": 1.150 }, // guessed - { "aperture": 1.8, "scale_factor": 1.110 }, // 15196/13584 - { "aperture": 2.0, "scale_factor": 1.080 }, // 14734/13584 - { "aperture": 2.2, "scale_factor": 1.050 }, // 14386/13584 - { "aperture": 2.5, "scale_factor": 1.040 }, // 14272/13584 - { "aperture": 2.8, "scale_factor": 1.030 }, // 14042/13584 - { "aperture": 3.2, "scale_factor": 1.015 }, // guessed - { "aperture": 3.5, "scale_factor": 1.000 } // guessed negligible - ] - } - }, - { // Quality A, f/1.6 aperture scale factor missing but safely guessed, ISO and aperture data by charlyw at RT forums - "make_model": "Canon EOS 7D Mark II", - "dcraw_matrix": [ 7268,-1082,-969,-4186,11839,2663,-825,2029,5839 ], // dng_v8.7 d65 - // "dcraw_matrix": [ 6285,-147,-821,-4080,11695,2714,-1045,2459,5497 ], // DXO D50 - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13500 }, // typical 13583 - LENR 13550 - { "iso": [ 160, 320, 640, 1250, 2500, 5000 ], "levels": 12500 }, // typical 12559 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000 ], "levels": 15200 }, // typical 15303 - LENR 15270,15260,15240,15220, - { "iso": [ 6400, 8000, 10000, 12800, 16000, 20000, 25600 ], "levels": 15100 }, // typical G1,G2 15303, R,B = 15430 LENR 15200 .. 15100 - { "iso": 51200, "levels": 16300 } // typical 16383 red 16371 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.6, f/1.0 (had no lenses to test with) */ - { "aperture": 1.4, "scale_factor": 1.200 }, // 15100/12277 exif - { "aperture": 1.6, "scale_factor": 1.100 }, // guessed - { "aperture": 1.8, "scale_factor": 1.050 }, // 14372/13583 - 13283 - { "aperture": 2.0, "scale_factor": 1.030 }, // 14034/13583 - 12973 - { "aperture": 2.2, "scale_factor": 1.015 }, // 13808/13583 - 12766 - { "aperture": 2.5, "scale_factor": 1.007 }, // 13696/13583 - 12662 - { "aperture": 2.8, "scale_factor": 1.007 }, // 13696/13583 - 12663 - { "aperture": 3.2, "scale_factor": 1.000 }, // 13583/13583 - 12559 - { "aperture": 3.5, "scale_factor": 1.000 } - ] - } - }, - - { // Quality A - ISO and aperture WL data by Ilias at Avclub gr forums - "make_model": "Canon EOS 40D", - "dcraw_matrix": [ 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 ], - "raw_crop": [ 30, 18, 3908, 2602 ], - "masked_areas": [ 20, 2, 2616, 20 ], - "ranges": { - "white": [ - { "iso": 100, "levels": 13700 }, // typical 13825 - { "iso": [ 125, 250, 500, 1000, 3200 ], "levels": 16280 }, // typical 16383 - { "iso": [ 160, 320, 640 ], "levels": 12600 }, // typical 12744 - { "iso": [ 200, 400 ], "levels": 16100 }, // typical 16224 - { "iso": 800, "levels": 15900 }, // gaussian histogram 15900-16224 - { "iso": 1600, "levels": 14900 }, // gaussian histogram 14900-15750 - { "iso": 1250, "levels": 11900 } // gaussian histogram 11900-12500 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the - typical 12700 white levels maxes out at "white_max" for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.265 }, // 16142/12744 - { "aperture": 1.6, "scale_factor": 1.145 }, // 15872/13825 - { "aperture": 1.8, "scale_factor": 1.090 }, // 15103/13825 - { "aperture": 2.0, "scale_factor": 1.035 }, // 14334/13825 - { "aperture": 2.2, "scale_factor": 1.005 }, // 13950/13825 - { "aperture": 2.5, "scale_factor": 1.000 } // 13825/13825 - ] - } - }, - { // Quality A, ISO and aperture WL data by Ayshih at Magic Lantern forums - "make_model": "Canon EOS 50D", - "dcraw_matrix": [ 4920,616,-593,-6493,13964,2784,-1774,3178,7005 ], - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13300 }, // typical 13432 - { "iso": [ 160, 320, 640, 1250 ], "levels": 12700 }, // typical 12790-12810 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 2500, 3200 ], "levels": 15630 }, // typical 15763-15733 - { "iso": [ 6400, 12800 ], "levels": 16200 } // typical 16383 - ], - "white_max": 16383, - "aperture_scaling": [ - { "aperture": 1.4, "scale_factor": 1.270 }, - { "aperture": 1.6, "scale_factor": 1.150 }, - { "aperture": 1.8, "scale_factor": 1.090 }, - { "aperture": 2.0, "scale_factor": 1.040 }, - { "aperture": 2.2, "scale_factor": 1.020 }, - { "aperture": 2.5, "scale_factor": 1.010 }, - { "aperture": 2.8, "scale_factor": 1.000 }, - { "aperture": 3.2, "scale_factor": 1.000 } - ] - } - }, - { // Quality A, ISO and aperture WL data copyed from Shalrath's 60D data at RawTherapee forums - "make_model": "Canon EOS 60Da", - "dcraw_matrix": [ 17492,-7240,-2023,-1791,10323,1701,-186,1329,5406 ], // 60Da dng d65 - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 - { "iso": [ 160, 320, 640, 1250, 2500 ], "levels": 12550 }, // typical 12650 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 5000, 6400, 12800 ], "levels": 15200 } // typical 15304 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the - typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.300 }, // gaps 81of301 - { "aperture": 1.6, "scale_factor": 1.200 }, - { "aperture": 1.8, "scale_factor": 1.140 }, - { "aperture": 2.0, "scale_factor": 1.080 }, // gaps 1of11 - { "aperture": 2.2, "scale_factor": 1.060 }, - { "aperture": 2.5, "scale_factor": 1.050 }, - { "aperture": 2.8, "scale_factor": 1.030 }, - { "aperture": 3.2, "scale_factor": 1.015 }, - { "aperture": 3.5, "scale_factor": 1.000 } // no sample but it would be negligible - ] - } - }, - { // Quality A, ISO and aperture WL data by Shalrath at RawTherapee forums - "make_model": "Canon EOS 60D", - "dcraw_matrix": [ 6719,-994,-925,-4408,12426,2211,-887,2129,6051 ], - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 - { "iso": [ 160, 320, 640, 1250, 2500 ], "levels": 12550 }, // typical 12650 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 5000, 6400, 12800 ], "levels": 15200 } // typical 15304 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the - typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.300 }, // gaps 81of301 - { "aperture": 1.6, "scale_factor": 1.200 }, - { "aperture": 1.8, "scale_factor": 1.140 }, - { "aperture": 2.0, "scale_factor": 1.080 }, // gaps 1of11 - { "aperture": 2.2, "scale_factor": 1.060 }, - { "aperture": 2.5, "scale_factor": 1.050 }, - { "aperture": 2.8, "scale_factor": 1.030 }, - { "aperture": 3.2, "scale_factor": 1.015 }, - { "aperture": 3.5, "scale_factor": 1.000 } // no sample but it would be negligible - ] - } - }, - { // Quality B, more aperture scale factors needed - "make_model": "Canon EOS 70D", - "dcraw_matrix": [ 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 ], // DNG D65 - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 - { "iso": [ 160, 320, 640, 1250, 2500, 5000 ], "levels": 12450 }, // typical 12559 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000, 10000 ], "levels": 15200 }, // typical 15303 - ISO 8000-10000 guessed - { "iso": [ 12800, 25600 ], "levels": 16200 } // typical 16383 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but even with the - 12500 white levels nearly maxes out for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.240 }, // guessed - { "aperture": 1.6, "scale_factor": 1.160 }, // guessed - { "aperture": 1.8, "scale_factor": 1.110 }, // 31of35 - { "aperture": 2.0, "scale_factor": 1.060 }, // guessed - { "aperture": 2.2, "scale_factor": 1.030 }, // guessed - { "aperture": 2.5, "scale_factor": 1.015 }, // guessed - { "aperture": 2.8, "scale_factor": 1.008 }, // 15432/15303 - { "aperture": 3.2, "scale_factor": 1.000 }, - { "aperture": 3.5, "scale_factor": 1.000 } - ] - } - }, - - { // Quality b, scaling factors missing but guessed safely - "make_model": [ "Canon EOS 1200D", "Canon EOS Rebel T5", "Canon EOS 600D", "Canon EOS Rebel T3i" ], - "dcraw_matrix": [ 6461,-907,-882,-4300,12184,2378,-819,1944,5931 ], // dcp D65 colormatrix2 - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 - { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000 ], "levels": 12550 }, // typical 12650 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000, 12800 ], "levels": 15200 } // typical 15303 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the - typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.290 }, // guessed from 60D data - { "aperture": 1.6, "scale_factor": 1.190 }, // guessed - { "aperture": 1.8, "scale_factor": 1.140 }, // guessed - { "aperture": 2.0, "scale_factor": 1.090 }, // 12293/11222 = 1.095 - { "aperture": 2.2, "scale_factor": 1.060 }, // 11971/11222 = 1.066 - { "aperture": 2.5, "scale_factor": 1.050 }, // guessed - { "aperture": 2.8, "scale_factor": 1.030 }, // iso100: 14042/13584=1.0336 - iso200 15820/15303 = 1.0348 - { "aperture": 3.2, "scale_factor": 1.000 }, // - { "aperture": 3.5, "scale_factor": 1.000 } // - ] - } - }, - - { // Quality A, only one scaling factor missing and guessed safely - "make_model": [ "Canon EOS 650D", "Canon EOS Rebel T4i" ], - "dcraw_matrix": [ 6602,-841,-939,-4472,12458,2247,-975,2039,6148 ], - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 - { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000 ], "levels": 12550 }, // typical 12650 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000 ], "levels": 15200 }, // typical 15303 - { "iso": [ 12800, 25600 ], "levels": 16200 } // typical 16383 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the - typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.200 }, // 16332/13583 - { "aperture": 1.6, "scale_factor": 1.080 }, // guessed - { "aperture": 1.8, "scale_factor": 1.055 }, // 14372/13583 - { "aperture": 2.0, "scale_factor": 1.030 }, // 14034/13583 - { "aperture": 2.2, "scale_factor": 1.025 }, // 13921/13583 - { "aperture": 2.5, "scale_factor": 1.020 }, // - { "aperture": 2.8, "scale_factor": 1.000 }, // - { "aperture": 3.2, "scale_factor": 1.000 }, // - { "aperture": 3.5, "scale_factor": 1.000 } // - ] - } - }, - - { // Quality C, aperture scale factors and intermediate ISOs missing but safely guessed - "make_model": [ "Canon EOS 750D", "Canon EOS Rebel T6i", "Canon EOS 760D", "Canon EOS Rebel T6s" ], - "dcraw_matrix": [ 6362,-823,-847,-4426,12109,2616,-743,1857,5635 ], // dng_v9.0 d65 - "raw_crop": [ 72, 34, 6024, 4022 ], // full size 6096x4056, official crop 84,46,6083,4045 - "masked_areas": [ 40, 16, 4000, 54 ], - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13300 }, // typical 13583 - { "iso": [ 160, 320, 640, 1250, 2500, 5000 ], "levels": 12500 }, // typical 12600 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000 ], "levels": 15200 }, // typical 15303 - { "iso": [ 6400, 8000, 10000, 12800, 16000, 20000 ], "levels": 15100 }, // typical 15303 - { "iso": 25600, "levels": 16300 } // typical 16383 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: all scale factors are guessed to be same as 7DII */ - { "aperture": 1.4, "scale_factor": 1.200 }, // guessed - { "aperture": 1.6, "scale_factor": 1.100 }, // guessed - { "aperture": 1.8, "scale_factor": 1.050 }, // guessed - { "aperture": 2.0, "scale_factor": 1.030 }, // guessed - { "aperture": 2.2, "scale_factor": 1.015 }, // guessed - { "aperture": 2.5, "scale_factor": 1.007 }, // guessed - { "aperture": 2.8, "scale_factor": 1.007 }, // guessed - { "aperture": 3.2, "scale_factor": 1.000 }, // guessed - { "aperture": 3.5, "scale_factor": 1.000 } - ] - } - }, - - { // Quality B, missing scaling factors are guessed safely from 650D relative data - "make_model": "Canon EOS M", - "dcraw_matrix": [ 6602,-841,-939,-4472,12458,2247,-975,2039,6148 ], - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 - { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000 ], "levels": 12550 }, // typical 12650 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000 ], "levels": 15200 }, // typical 15303 - { "iso": [ 12800, 25600 ], "levels": 16200 } // typical 16383 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the - typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.200 }, // guessed - { "aperture": 1.6, "scale_factor": 1.080 }, // guessed - { "aperture": 1.8, "scale_factor": 1.055 }, // guessed - { "aperture": 2.0, "scale_factor": 1.030 }, // 15821/15303 - { "aperture": 2.2, "scale_factor": 1.025 }, // 15691/15303 - { "aperture": 2.5, "scale_factor": 1.020 }, // 12947/12650 - { "aperture": 2.8, "scale_factor": 1.000 }, // - { "aperture": 3.2, "scale_factor": 1.000 }, // - { "aperture": 3.5, "scale_factor": 1.000 } // - ] - } - }, - - { // Quality C, White Levels not properly indicated, aperture scaling..missing scaling factors are guessed - "make_model": "Canon EOS M3", - "dcraw_matrix": [ 6362,-823,-847,-4426,12109,2616,-743,1857,5635 ], // DNG_V8.8 D65 - "raw_crop": [ 72, 34, 6024, 4022 ], // full size 6096x4056, official crop 84,46,6083,4045 - "masked_areas": [ 40, 16, 4000, 54 ], - "ranges": { - "white": [ - { "iso": [ 100, 125, 160 ], "levels": 16300 }, // 16383 - { "iso": [ 320, 640, 1250, 2500, 5000, 10000 ], "levels": 12600 }, // 12632..14500 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000 ], "levels": 15000 }, // 15095, 15488 - { "iso": [ 6400, 8000, 12800, 25600 ], "levels": 16200 } // 16383 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: need for more data to properly fill all scale factors */ - { "aperture": 1.4, "scale_factor": 1.200 }, // guessed - { "aperture": 1.6, "scale_factor": 1.080 }, // guessed - { "aperture": 1.8, "scale_factor": 1.055 }, // guessed - { "aperture": 2.0, "scale_factor": 1.030 }, // guessed - { "aperture": 2.2, "scale_factor": 1.025 }, // guessed - { "aperture": 2.5, "scale_factor": 1.020 }, // guessed - { "aperture": 2.8, "scale_factor": 1.000 }, // - { "aperture": 3.2, "scale_factor": 1.000 }, // - { "aperture": 3.5, "scale_factor": 1.000 } // - ] - } - }, - { /* Quality B, needs a way to auto apply 3/2 or 4/3 crops (read exif tags ..) to work better with auto distortion, - for the moment just comment-uncomment the desired raw crop */ - "make_model": "Canon PowerShot G1 X Mark II", - "dcraw_matrix": [ 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 ], // D65 matrix from adobe dcp - // "raw_crop": [ 80, 50, 4400, 3316 ], // full frame 4480x3366 borders 80,50 - much shade in corners, no/wrong auto distortion - // "raw_crop": [ 104, 144, 4360, 3128 ], // Mixed best average frame, width is 4352 from 3/2, height 3120 from 4/3 - auto distortion does not work correctly - // "raw_crop": [ 200, 144, 4168, 3128 ], // Optional official 4/3 frame 4160x3120, 4pix borders, Left Border 204-4, Top Border 148-4 - "raw_crop": [ 104, 252, 4360, 2912 ], // Default official 3/2 frame 4352X2904, 4pix borders, Left Border 108-4, Top border 256-4 - "masked_areas": [ 148, 2, 3340, 78 ], - "ranges": { "white": 16300 } - }, - - { // Quality B, - "make_model": "Canon PowerShot G7 X", - "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 ], // DNG_V8.7 D65 - // "raw_crop": [ 116, 24, 5504, 3680 ], // Sensor size 5632x3710. Largest useful frame 120-5616X28-3702 = 5504x3682, 4pix RTborders, Left Border 120-4, Top border 28-4 - "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 - "masked_areas": [ 40, 4, 3680, 76 ], - "ranges": { "white": 4080 } - }, - - { // Quality B, - "make_model": "Canon PowerShot G3 X", - "dcraw_matrix": [ 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 ], // DNG_V9.1.1 D65 - "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 - "masked_areas": [ 40, 4, 3680, 76 ], - "ranges": { "white": 16300 } - }, - - { // Quality A, changes for raw crop which is wrong (larger) in Dcraw - "make_model": "Canon PowerShot S120", - "dcraw_matrix": [ 6961,-1685,-695,-4625,12945,1836,-1114,2152,5518 ], - "raw_crop": [ 120, 30, 4024, 3030 ], - "masked_areas": [ 32, 2, 3028, 80 ], - "ranges": { "white": 4050 } - }, - - { // Quality A, changes for raw crop which is optimistic in Dcraw - "make_model": "Canon PowerShot G12", - "dcraw_matrix": [ 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 ], - // "raw_crop": [ 62, 18, 3666, 2748 ],// max usable - "raw_crop": [ 68, 20, 3656, 2744 ],// equal to official Canon frame, 72,24,3719,2759 = 3648x2736 - "masked_areas": [ 24, 40, 2770, 44 ],// as declared in maker data - "ranges": { "white": 4080 } // - }, - - { // Quality B - "make_model": "Canon PowerShot SX60 HS", - "dcraw_matrix": [ 13161,-5451,-1344,-1989,10654,1531,-47,1271,4955 ], // DNG_V8.7 D65 - "raw_crop": [ 120, 34, 4616, 3464 ], // full raw 4768x3516, Usable 96,16,4672,3498 - Canon official 4608x3456 left 124 top 38, - "masked_areas": [ 20, 2, 3480, 80 ], - "ranges": { "white": 4050 } // nominal 4080-4093 - }, - - { // Quality A - "make_model": "FUJIFILM S1", - "dcraw_matrix": [ 12297,-4882,-1202,-2106,10691,1623,-88,1312,4790 ] // DNG_v8.5 D65 - }, - - { // Quality B, - "make_model": [ "FUJIFILM X100S", "FUJIFILM X100T" ], - "dcraw_matrix": [ 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 ], // DNG_v8.7 D65 - "ranges": { "white": 16100 } - }, - - { // Quality B - "make_model": "FUJIFILM X-A2", - "dcraw_matrix": [ 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 ], // DNG D65 - "ranges": { "white": 4050 } - }, - { // Quality B - "make_model": [ "FUJIFILM X-T1", "FUJIFILM X-T10", "FUJIFILM X-E2" ], - "dcraw_matrix": [ 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 ], // DNG D65 -// "dcraw_matrix": [ 9289,-3279,-632,-3539,11137,2758,-1049,1950,6544 ], // X-RITE D55 - "ranges": { "white": 16100 } - }, - - { // Quality B - "make_model": "FUJIFILM X30", - "dcraw_matrix": [ 12328,-5256,-1144,-4469,12927,1675,-87,1291,4351 ], // DNG_v8.7 D65 - "ranges": { "white": 4040 } - }, - - { // Quality B - "make_model": "FUJIFILM XQ2", - "dcraw_matrix": [ 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 ], // DNG_v8.8 D65 - "ranges": { "white": 4040 } - }, - { // Quality A - "make_model": [ "Nikon 1 V3", "Nikon 1 J4" ], // Same format - "dcraw_matrix": [ 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 ], // matrix from DNG_v8.5 d65 - // "dcraw_matrix": [ 5306,-1066,-469,-3865,11189,3076,-399,1341,5120 ], // matrix dXo D50, - "ranges": { "white": 4080 } // Black is auto extracted from exif, lower WL to 4080 from 4095 due to some non linearity detected at raw highlights - }, - - { // Quality B, - "make_model": "Nikon 1 J5", // - "dcraw_matrix": [ 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 ], // DNG_v9.1 D65 - // "dcraw_matrix": [ 7651,-2102,-751,-3299,11101,1651,-1011,2242,5770 ], // matrix from ICC converted to Dcraw format XYZ on ImagingResource stillife sample - "ranges": { - "white": [ - { "iso": [ 160, 200 ], "levels": 4000 }, // typical G1/G2 4020-4028, R/B 4088 - { "iso": [ 400, 800, 1600, 3200 ], "levels": 4000 }, // g1/g2 4030-4040, r/b 4088 - { "iso": [ 6400, 12800 ], "levels": 4080 } // 4090 - ] - } - }, - - { // Quality A, - "make_model": "Nikon 1 S2", // - "dcraw_matrix": [ 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 ], // matrix from DNG_v8.5 d65 - "ranges": { "white": 4080 } // BL autodetected from exif - }, - - { // quality B, lacks aperture and ISO scaling, known to exist, but little to gain as the levels are so close to white_max - "make_model": "Nikon D7000", - "dcraw_matrix": [ 7530,-1942,-255,-4318,11390,3362,-926,1694,7649 ], // matrix provided by Tanveer(tsk1979) - "ranges": { - // measured at ISO 100. ISO differences not measured, but known to exist - "white": [ 16370, 15760, 16370 ], // typical R 16383, G 15778, B 16383 - "white_max": 16383 - // aperture scaling not measured, but known to exist, at f/1.8 the G channels hits white_max - } - }, - - { // Quality B, aperture scaling used to scale WL at safer levels - "make_model": "Nikon D5300", - "dcraw_matrix": [ 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 ], // adobe dng_v8.8 d65 - "ranges": { "white": 16300 } // attention.. WL value is for 14bit files, has to be 4070 for 12bit files. WL typical 16383 set to 16300 for safety - }, - - { // Quality B, aperture scaling used to scale WL at safer levels - "make_model": "Nikon D5500", - "dcraw_matrix": [ 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 ], // adobe dng_v9.0 d65 - "ranges": { "white": 16300 } // attention.. WL value is for 14bit files, has to be 4070 for 12bit files. WL typical 16383 set to 16300 for safety - }, - - { // Quality B, color matrix from DNG_v9.0 instead of internal Dcraw_v9.25_r1.475, - "make_model": "Nikon D7200", - "dcraw_matrix": [ 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 ], // adobe dng_v9.0 d65 - "ranges": { "white": 16300 } // attention.. WL values are for 14bit files, has to be WL4070 for 12bit files. WL typical 16383 set to 16300 for safety, - }, - - { // quality B, samples by joachip at RT forums, are measures at long exposures with LongExposureNoiseReduction - // aperture scaling known to exist, but little to gain as the levels are so close to white_max - "make_model": "Nikon D600", - "dcraw_matrix": [ 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 ], // dcp d65 - // "raw_crop": [ 0, 0, 6034, 4028 ], // dcraw - "ranges": { - "white": [ - { "iso": [ 50, 100 ], "levels": [ 15800, 15800, 15350 ] }, // typical G1/G2/R 15879, B 15395-15670 lowered to 15800, 15350, 3969 B3917 - { "iso": [ 200, 400, 800 ], "levels": [ 16300, 15700, 16300 ] }, // 15878, 16383 - { "iso": 1000, "levels": [ 16300, 16100, 16300 ] }, // 12bit lossless r4095, 3981-10, b4041- 12bit lossy r,g1,g2 3961 - b3917, - { "iso": 1600, "levels": [ 16300, 16100, 16300 ] }, // 16145-165, 16383 - { "iso": [ 3200, 6400, 12800, 25600 ], "levels": [ 16300, 16300, 16300 ] } // 16383 - ], - "white_max": 16383 - } - }, - { // quality B, lacks WL measures at intermediate ISOs (160-250-320 ..) and measures at long exposures with LongExposureNoiseReduction - // aperture scaling known to exist, but little to gain as the levels are so close to white_max - "make_model": "Nikon D610", - "dcraw_matrix": [ 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 ], // dcp d65 - "raw_crop": [ 0, 0, 6034, 4028 ], // Dcraw has no raw crop for D610 - "ranges": { - "white": [ - { "iso": [ 50, 100 ], "levels": [ 15800, 15700, 15800 ] }, // typical G1/G2 15778, R/B 15879 lowered to 15700, 15800 for possible WL distribution under LENR - { "iso": [ 200, 400, 800 ], "levels": [ 16300, 15700, 16300 ] }, // 15878, 16383 - { "iso": 1600, "levels": [ 16300, 16100, 16300 ] }, // 16145-165, 16383 - { "iso": [ 3200, 6400, 12800, 25600 ], "levels": [ 16300, 16300, 16300 ] } // 16383 - ], - "white_max": 16383 - } - }, - - { // quality B; Data from RusselCottrell at RT forums. sensor is not uniform - "make_model": "Nikon D700", - "dcraw_matrix": [ 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 ], - "ranges": { "white": 15750 } // Non linearities start at 15750 (hi ISOs) 15850 (low ISOs) with long exposures (>2sec) and LENR ON .. nominal 15892 - // white 15750 is correct for 14bit files, 12 bit files need white level at 3900 - }, - - { // Quality B, - "make_model": "Nikon D750", - "dcraw_matrix": [ 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 ], // adobe dcp d65 DNGv8.7 - "ranges": { "white": 16300 } // attention.. WL values are for 14bit files, has to be WL4070 for 12bit files. WL typical 16383 set to 16300 for safety - }, - - { // quality B; Data from RussellCottrell at RT forums. Largest aperture scale factor is 1.013, about 1/50th of a stop - "make_model": "Nikon D800E", - "dcraw_matrix": [ 7866,-2108,-555,-4869,12483,2681,-1176,2069,7501 ], // D800/D800E from dcraw.c - "ranges": { - "white": [ - { "iso": [ 100, 125, 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250 ], "levels": [ 16300, 15700, 16300 ] }, // 15779-15781 - { "iso": [ 1600 ], "levels": 16000 }, // 16085-16113 - { "iso": [ 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 16300 } // 16383 - ] - } - }, - { // quality B, WL set at 16300 from nominal 16380 for possible non linearities with LENR - "make_model": "Nikon D810", - "dcraw_matrix": [ 9369,-3195,-791,-4488,12430,2301,-893,1796,6872 ], // dcp_v8.6 d65 - "raw_crop": [ 0, 0, 7380, 4928 ], // Official raw crop 7380x4928, - "ranges": { "white": 16300 } // attention WL 16300 is for 14bit raws and has to be 4070 for 12 bit raws. Typical WL at 16383 - }, - { // Quality b, 16Mp and 64Mp raw frames - "make_model": "OLYMPUS E-M5MarkII", - "dcraw_matrix": [ 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 ], // DNG_v8.8 D65 - "raw_crop": [ 0, 0, -6, -6 ], // largest valid, full 64Mp 9280x6938, official crop 0 0 9216 6912 - safe 5755 - "ranges": { - "white": [ - { "iso": [ 100, 200 ], "levels": 3950 }, // normal 4080-4095, HR Dpreview 4047, IR 3956 - { "iso": [ 400, 800, 1600, 3200 ], "levels": 4070 }, // 4070-4095 - { "iso": [ 6400, 12800, 25600 ], "levels": 4040 } // 4000-4095 - ] - } - }, - - { // Quality b, crop correction - "make_model": "OLYMPUS E-M10", - "dcraw_matrix": [ 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 ], - "raw_crop": [ 0, 0, 4624, 3472 ], // largest valid - full frame is 4640x3472 -// "raw_crop": [ 4, 4, 4616, 3464 ], // olympus jpeg crop 8, 8, 4608, 3456 - "ranges": { "white": 4080 } - }, - { // Quality A, white level correction - "make_model": "OLYMPUS E-PM2", - "dcraw_matrix": [ 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 ], - "ranges": { "white": 4040 } // nominal 4056 - }, - - { // Quality B, with long exposure noise reduction White Level gets WL-BL = around 256_12bit levels less - "make_model": "OLYMPUS E-PL7", - "dcraw_matrix": [ 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 ], // DNG_V8.7 D65 - "ranges": { "white": 4080 } // nominal 4093 - }, - - { // Quality B, per ISO WL measures missing - "make_model": "OLYMPUS SH-2", - "dcraw_matrix": [ 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 ], // DNG_V9.1 D65 - "ranges": { "white": 4050 } // safe for worst case detected, nominal is 4093 - }, - - /* since Dcraw_v9.21 Panasonic base BL is read from exif (tags 0x001c BlackLevelRed15 is BL offstet. - Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset, 0x001d BlackLevelGreen, 0x001e BlackLevelBlue - and we define here the needed offset of around 15. The total BL is base+offset */ - - { // Quality B, CameraPhone, some samples are missing but has the same sensor as FZ1000 .. - "make_model": "Panasonic DMC-CM1", - "dcraw_matrix": [ 8770,-3194,-820,-2871,11281,1803,-513,1552,4434 ], // dcp_v8.7 d65 - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": 80, "levels": 3600 }, // exif:3277 distribution peak at 3700 up to +/- 100 - { "iso": [ 100, 125, 200, 400, 800, 1600 ], "levels": 4050 }, // exif 4095 distribution 4050-4095 - { "iso": [ 3200, 6400, 12600, 25600 ], "levels": 4080 } // exif 4095 distribution 4080-4095 - ] - } - }, - - { // Quality A , replicated from rawimage.cc - "make_model": "Panasonic DMC-FZ150", - "dcraw_matrix": [ 10435,-3208,-72,-2293,10506,2067,-486,1725,4682 ], // RT, copy from custom dcp d55 - "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset - }, - - { // Quality Β, - "make_model": [ "Panasonic DMC-FZ300", "Panasonic DMC-FZ330" ], - "dcraw_matrix": [ 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 ], // DNG-V9.1.1 - "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset - }, - - { // Quality A, samples by helices at Rt forums - "make_model": [ "Panasonic DMC-FZ1000", "Leica V-LUX (Typ 114)" ], - "dcraw_matrix": [ 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 ], // dcp_v8.6 d65 - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": 80, "levels": 3600 }, // exif:3277 distribution peak at 3700 up to +/- 100 - { "iso": [ 100, 125, 200, 400, 800, 1600 ], "levels": 4050 }, // exif 4095 distribution 4050-4095 - { "iso": [ 3200, 6400, 12600, 25600 ], "levels": 4080 } // exif 4095 distribution 4080-4095 - ] - } - }, - - { // Quality A - "make_model": [ "Panasonic DMC-LF1", "Leica C (Typ 112)" ], - "dcraw_matrix": [ 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 ], - "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset - }, - { // Quality A - "make_model": [ "Panasonic DMC-TZ60", "Panasonic DMC-TZ61", "Panasonic DMC-ZS40", "Panasonic DMC-ZS41" ], - "dcraw_matrix": [ 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 ], // matrix from Adobe dcp v8.4 - "raw_crop": [ 8, 8, -8, -8 ], // crop according to exif 4896 X 3672 plus 4 pixels borders. RT's frame gets smaller than Dcraw but works better with auto distortion - "ranges": { "black": 14, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset - }, - { // Quality B, - "make_model": [ "Panasonic DMC-TZ70", "Panasonic DMC-TZ71", "Panasonic DMC-ZS50", "Panasonic DMC-ZS51" ], - "dcraw_matrix": [ 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 ], // DNG_V8.8 D65 - "raw_crop": [ 4, 4, -4, -4 ], // full raw 4/3 4144x3016 8,8,3008,4008 = 4000X3000. RT's frame gets smaller than Dcraw but works better with auto distortion - "ranges": { "black": 14, "white": 4050 } // 12+1+1 is BL offset - }, - - // Panasonic DMC-FZ150,G10,G1,G2,G3,G5,GF1,GF2,GF3 are included as overwrites of the same items of rawimage.cc to test the Dcraw9.21 patch - - { // Quality A, Replicated from rawimage.cc - "make_model": [ "Panasonic DMC-G10", "Panasonic DMC-G2" ], - "dcraw_matrix": [ 8310,-1811,-960,-4941,12990,2151,-1378,2468,6860 ], // Colin Walker - "ranges": { - "black": 15, // 15 is black offset, Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:3967 distribution peak at 3967 +/- up to 50 - { "iso": [ 1600, 3200, 6400 ], "levels": 4060 } // exif 3967, histogram peak 4095 and distribution down to 4070 - ] - } - }, - { // Quality A, Replicated from rawimage.cc - "make_model": "Panasonic DMC-G1", - "dcraw_matrix": [ 7477,-1615,-651,-5016,12769,2506,-1380,2475,7240 ], // Colin Walker - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:4095 distribution peak at 3977 +/- up to 50 - { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 - ] - } - }, - { // Quality A, Replicated from rawimage.cc - "make_model": "Panasonic DMC-G3", - "dcraw_matrix": [ 6051,-1406,-671,-4015,11505,2868,-1654,2667,6219 ], // Colin Walker - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": 4060 } // exif:4095 normal distribution 4080-4095, 4070-4095 on long exposure NR - }, - { // Quality A, Replicated from rawimage.cc - "make_model": "Panasonic DMC-G5", - "dcraw_matrix": [ 7122,-2092,-419,-4643,11769,3283,-1363,2413,5944 ], // RT - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": 4060 } // exif:4095 normal distribution 4080-4095, 4070-4095 on long exposure NR - }, - { // Quality A, Replicated from rawimage.cc - "make_model": "Panasonic DMC-GF1", - "dcraw_matrix": [ 7863,-2080,-668,-4623,12331,2578,-1020,2066,7266 ], // Colin Walker - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:4095 distribution peak at 3977 +/- up to 50 - { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 - ] - } - }, - - { // Quality A, Replicated from rawimage.cc - "make_model": "Panasonic DMC-GF2", - "dcraw_matrix": [ 7694,-1791,-745,-4917,12818,2332,-1221,2322,7197 ], // Colin Walker - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": 4050 } // exif:4095 normal distribution 4080-4095, 4050-4095 on long exposure NR - }, - { // Quality A, Replicated from rawimage.cc - "make_model": "Panasonic DMC-GF3", - "dcraw_matrix": [ 8074,-1846,-861,-5026,12999,2239,-1320,2375,7422 ], // Colin Walker - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": 4050 } // exif:4095 normal distribution 4080-4095, 4050-4095 on long exposure NR - }, - { // Quality A, Replicated from rawimage.cc - "make_model": "Panasonic DMC-GH1", - "dcraw_matrix": [ 6360,-1557,-375,-4201,11504,3086,-1378,2518,5843 ], // Colin Walker - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": [ 100, 200, 400, 800 ], "levels": 3930 }, // exif:4095 distribution peak at 3982 +/- up to 50 - { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 - ] - } - }, - { // Quality A, Replicated from rawimage.cc - "make_model": "Panasonic DMC-GH2", - // "dcraw_matrix": [ 6855,-1765,-456,-4223,11600,2996,-1450,2602,5761 ], // Colin Walker - disabled due to problems with underwater - "dcraw_matrix": [ 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 ], // Dcraw d65 - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": [ 100, 200, 400, 800 ], "levels": 3930 }, // exif:4095 distribution peak at 3982 +/- up to 50 - { "iso": [ 1600, 3200, 6400, 12800 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 - ] - } - }, - - { // Quality B, variable WL - "make_model": "Panasonic DMC-GH3", - "dcraw_matrix": [ 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 ], // dcp d65 - "ranges": { - "black": 16, // 16 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": 125, "levels": 3500 }, // gaussian 3600-4095 - { "iso": [ 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 - ] - } - }, - - { // Quality B, some ISO WLevels are safely guessed - "make_model": "Panasonic DMC-GH4", - "dcraw_matrix": [ 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 ], // dng_v8.5 d65 - "ranges": { - "black": 16, // 16 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": 100, "levels": 2700 }, // gaussian center at 2870-2920 range +/- 150, exif 2111 - { "iso": 125, "levels": 3100 }, // guessed - { "iso": [ 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 - ] - } - }, - - { // Quality A, - "make_model": "Panasonic DMC-GM1", - "dcraw_matrix": [ 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 ], - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": 125, "levels": 3100 }, // bell shape 3150-3650 - exif 2616 - { "iso": 160, "levels": 3600 }, // guessed from relative GX7 data - { "iso": [ 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 - ] - } - }, - - { // Quality B, uncertainty about ISO100 WL - "make_model": "Panasonic DMC-GM5", - "dcraw_matrix": [ 8238,-3244,-679,-3921,11814,2384,-836,2022,5852 ], // dng_v8.7 d65 - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": 100, "levels": 2800 }, // bell shape 2850-3250 - exif 2111 - { "iso": [ 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 - ] - } - }, - { // Quality A, - "make_model": [ "Panasonic DMC-GX7", "Panasonic DMC-GF7" ], - "dcraw_matrix": [ 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 ], - "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": 125, "levels": 3100 }, - { "iso": 160, "levels": 3600 }, - { "iso": [ 200, 250, 320, 400,500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 - ] - } - }, - - { // Quality A, - "make_model": [ "Panasonic DMC-G7", "Panasonic DMC-G70" ], - "dcraw_matrix": [ 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 ],// DNG_v9.1 D65 - // "dcraw_matrix": [ 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 ], // LX100, DNG_V8.7 d65 - "ranges": { - "black": 16, // 16 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": 100, "levels": 2300 }, // gaussian 2300-2700 exif_linearitylimit 2111 - { "iso": 125, "levels": 3180 }, // gaussian 3200-3600 exif_linearitylimit 2626 - { "iso": [ 160, 200, 250, 320, 400,500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 - ] - } - }, - { // Quality B, - "make_model": "Panasonic DMC-GX8", - "dcraw_matrix": [ 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 ], // DNG_v9.1.1 D65 - "ranges": { - "black": 15, // 16 is BL offstet. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset - "white": [ - { "iso": 100, "levels": 2300 }, // gaussian 2300-2700 exif_linearitylimit 2111 - { "iso": 125, "levels": 3180 }, // guessed gaussian 3200-3600 exif_linearitylimit 2626 - { "iso": [ 160, 200, 250, 320, 400,500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 - ] - } - }, - { // Quality B, uncertainty about ISO 100 WL - "make_model": [ "Panasonic DMC-LX100", "Leica D-LUX (Typ 109)" ], - "dcraw_matrix": [ 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 ], // DNG_V8.7 d65 - // "dcraw_matrix": [ 6538,-1614,-549,-5475,13096,2646,-1780,2799,5612 ], // calculated from DxO D50 - "ranges": { - "black": 15, // 15 is BL offset calculated from exif data. - "white": [ - { "iso": 100, "levels": 2300 }, // gaussian 2400-2700 exif_linearitylimit 2111 - { "iso": [ 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 - ] - } - }, - - { // Quality B, intermediate ISOs info missing - "make_model": [ "RICOH PENTAX K-3", "PENTAX K-3" ], - "dcraw_matrix": [ 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 ], // adobe dcp d65 -// "dcraw_matrix": [ 8542,-2581,-1144,-3995,12301,1881,863,1514,5755 ], // pentax DNG -// "dcraw_matrix": [ 6464,-1574,-422,-5324,12712,2934,-1129,1724,6900 ], // DxO - "raw_crop": [ 10, 4, 6028, 4024 ], - "ranges": { - "white": [ - { "iso": 100, "levels": 16310 }, // 16317 or 16350 - { "iso": 200, "levels": 16120 }, // 16254 or 16125 - { "iso": 400, "levels": 15860 }, // 16125 or 15868 - { "iso": 800, "levels": 15360 }, // 15868 or 15364-15370 - { "iso": [ 1600, 3200, 6400, 12800, 25600, 51200 ], "levels": 16300 } // 16383 - pentax dng tag is 15868-15350 - ] - } - }, - - { // Quality B, intermediate ISOs info missing, spread due to blackframe subtraction guessed to be around 10levels - "make_model": "PENTAX K10D", - "dcraw_matrix": [ 9566,-2863,-803,-7170,15172,2112,-818,803,9705 ], // adobe DNG d65 - // "raw_crop": [ 0, 0, 3888, 2608 ], - "ranges": { - "white": [ - { "iso": 100, "levels": 4080 }, // R,G1,B = 4095 G2= 4087 - { "iso": 200, "levels": 4080 }, // R,G1,B = 4093-94 G2= 4087or94 - { "iso": 400, "levels": 4080 }, // R,G1 = 4093-94, B=4094 G2= 4087or93or94 - { "iso": 800, "levels": 4070 }, // R,G1 = 4091-4093, B=4091-92 G2= 4078or82or84-86 - { "iso": [ 1600, 3200 ], "levels": 4060 } // 4067or4073-76 - ] - } - }, - - { // Quality B, corrections for raw crop vs Dcraw9.21, matched to Samsung's default - "make_model": "Samsung NX mini", - "dcraw_matrix": [ 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 ], // dng 8.6 d65 - "raw_crop": [ 128, 36, 5480, 3656 ], // jpeg 5472x3648 - full raw: 5664 x 3710 - Samsung's official crop: 132, 40, 5604, 3688 - "ranges": { "white": 4030 } // double clipping point for each channel at a) 4095 and b) bell distribution with peak at 4038 .. used the conservative one - }, - { // Quality A, Conflict with "Samsung NX30" in Dcraw_v9.21_r1.414, frame corrections and color data - "make_model": "Samsung NX3000", - "dcraw_matrix": [ 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 ], // DNG_v8.7.1 D65 - "raw_crop": [ 92, 38, 5480, 3656 ] // jpeg 5472x3648 - full raw: 5600 x 3714 - Samsung's official crop: 96, 42, 5568, 3690 - }, - - { // Quality B, RT normally use the embedded data with DNGs but because various DNG use different color matrix adobe_coeff setting is used in dcraw.cc to always use the data from camconst.json for NX1 - "make_model": [ "Samsung NX1", "Samsung NX500" ], - "dcraw_matrix": [ 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 ], // DNG_v8.7 D65 - // "dcraw_matrix": [ 13298,-6099,-296,-5243,16153,-1235,-508,1220,7758 ], // DNG_v8.7 Standard Light A - // "dcraw_matrix": [ 9598,-3268,-634,-5678,14795,824,-1255,2675,4523 ], // SAMSUNG DNG CONVERTER - "ranges": { - "white": [ - { "iso": 100, "levels": 16000 }, // typical 16084, LE 16120 and 16383, LENR 16280 - { "iso": [ 200, 400, 800, 1600, 3200, 6400, 12800 ], "levels": 16300 }, // 16383 - { "iso": [ 25600, 51200 ], "levels": 16300 } // 16383 - ] - } - }, - - { // Quality c, corrections for frame size, black and white levels not declared properly - "make_model": "Sigma SD9", - "dcraw_matrix": [ 14996,-3468,-1425,5576,3642,972,1761,3773,3720 ], // experimental calculated from sun0.icc data - "ranges": { "black": 0, "white": 16383 },// black is already subtracted by dcraw, white copied from x3dump data - "raw_crop": [ 20, 8, -18, -12 ] - }, - { // Quality c, corrections for frame size, black level not declared properly - "make_model": "Sigma SD10", - "dcraw_matrix": [ 12555,-1865,-1125,5093,4120,867,1929,3810,3507 ], // experimental calculated from .icc data - "ranges": { "black": 0, "white": 16383 },// black is already subtracted by dcraw, white copied from x3dump data - // "raw_crop": [ 0, 0, -0, -0 ] - "raw_crop": [ 20, 8, -18, -12 ] - }, - { // Quality c, corrections for frame size, black and white levels not declared properly - "make_model": "Sigma SD14", - "dcraw_matrix": [ 16411,-4764,-2383,8110,2603,-645,3135,3878,1984 ], // experimental inverted icc wp12 - build with BL=15 - // "dcraw_matrix": [ 13804,-4156,-1896,6917,1909,-431,2768,2989,1741 ], // experimental inverted icc wp10 - build with BL=15 - "ranges": { "black": 0, "white": 16383 },// peripheral black stripes give BL around 37 - "raw_crop": [ 0, 0, -0, -0 ] - // "raw_crop": [ 18, 12, 2652, 1768 ] - }, - - { // Quality c, correction for frame width - "make_model": "Sigma SD1", - "dcraw_matrix": [ 5270,42,-814,3737,5506,124,1112,9714,4510 ], // experimental from icm 1.04477,-0.74838,1.01617, -0.54028,2.52690,-3.83257, 0.54869,-0.69556,3.73746 - "ranges": { "black": 16, "white": 4070 },// BL is 16 or 31, should be measured at the horizontal black stripe at the top - "raw_crop": [ 12, 52, -110, -8 ] - }, - { // Quality C, correction for frame width, color matrix investigated .. - "make_model": "Sigma SD1 Merrill", - "dcraw_matrix": [ 7211,-1577,-769,4996,3428,440,2717,7117,4699 ], // experimental inverted icc cloudy8140 d65 - // "dcraw_matrix": [ 5666,139,-892,3780,5428,270,1366,9757,4526 ], // experimental inverted icc sunny8161 - // "dcraw_matrix": [ 10288,-2449,-1718,8976,1868,-1608,7011,5039,-249 ], // experimental inverted icc tungsten8130 wp11 - // "dcraw_matrix": [ 5864,679,-1491,2963,7635,-919,-640,13738,2790 ], // experimental inverted icc sunny8160 - // "dcraw_matrix": [ 14032,-2231,-1016,-5263,14816,170,-112,183,9113 ], // hardcoded - "ranges": { "black": 16, "white": 4070 }, // BL is 16 or 31, should be measured at the horizontal black stripe at the top - "raw_crop": [ 12, 52, -110, -8 ] // for small size all numbers/2 - }, - { // Quality C, correction for frame width, color matrix guessed .. - "make_model": [ "Sigma DP1 Merrill", "Sigma DP2 Merrill", "Sigma DP3 Merrill" ], - "dcraw_matrix": [ 5666,139,-892,3780,5428,270,1366,9757,4526 ], // copy fron SD1 Merrill icc cloudy8140 d65 - "ranges": { "black": 16, "white": 4070 }, // BL is 16 or 31, should be measured at the horizontal black stripe at the bottom - "raw_crop": [ 12, 0, -110, -62 ] // for small size all numbers/2 - }, - - - { // Quality A, correction for color matrix from Colin Walker's d50 to dng d65 - "make_model": "Sony NEX-C3", - // "dcraw_matrix": [ 5130,-1055,-269,-4473,11797,3050,-701,1310,7121 ], // Colin walker's d50 kept for possible consistency issues - "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], - "ranges": { "black": 512, "white": 16300 } - }, - - { // Quality A, correction for frame width - "make_model": "Sony NEX-5N", - "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], - "raw_crop": [ 0, 0, 4920, 3276 ], - "ranges": { "black": 512, "white": 16300 } - }, - { // Quality A, - "make_model": "Sony ILCA-77M2", - "dcraw_matrix": [ 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 ], // adobe dcp d65 - "raw_crop": [ 0, 0, 6024, 4024 ], - "ranges": { "black": 512, "white": 16300 } - }, - - { // Quality A, correction for frame width - "make_model": [ "Sony ILCE-3000", "Sony ILCE-3500", "Sony ILCE-5000", "Sony ILCE-QX1" ], - "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], // adobe dcp d65 - "ranges": { "black": 512, "white": 16300 }, - "raw_crop": [ 0, 0, 5476, 3656 ] - }, - { // Quality A, - "make_model": "Sony ILCE-5100", - "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], // adobe dcp d65 - "raw_crop": [ 0, 0, 6024, 4024 ], - "ranges": { "black": 512, "white": 16300 } - }, - { // Quality A - "make_model": "Sony ILCE-6000", - "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], // adobe dcp d65 - "raw_crop": [ 0, 0, 6024, 4024 ], - "ranges": { "black": 512, "white": 16300 } - }, - { // Quality A - "make_model": "Sony ILCE-7M2", - "dcraw_matrix": [ 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 ], // DNGv8.7.1 - "ranges": { "black": 512, "white": 16300 } - }, - { // Quality A, correction for frame width - "make_model": "Sony ILCE-7R", - "dcraw_matrix": [ 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 ], - "raw_crop": [ 0, 0, 7372, 4920 ], - "ranges": { "black": 512, "white": 16300 } - }, - - { // Quality B, correction for frame width, crop modes not covered - "make_model": "Sony ILCE-7RM2", - "dcraw_matrix": [ 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 ], // DNG_v9.1.1 D65 - "raw_crop": [ 0, 0, 7964, 5320 ], // full raw frame 8000x5320 - 36 rightmost columns are garbage - "ranges": { "black": 512, "white": 16300 } - }, - - { // Quality B, correction for frame width - "make_model": "Sony ILCE-7S", - "dcraw_matrix": [ 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 ], // DNG D65 - "raw_crop": [ 0, 0, 4254, 2848 ], - "ranges": { "black": 512, "white": 16300 } - }, - { // Quality A, - "make_model": [ "Sony DSC-RX100M3", "Sony DSC-RX100M4" ], - "dcraw_matrix": [ 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 ], // DNG_v9.1.1 D65 - "ranges": { "black": 800, "white": 16300 } - }, - { // Quality B, - "make_model": "Sony DSC-RX10M2", - "dcraw_matrix": [ 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 ], // DNG_v9.1.1 D65 - "ranges": { "black": 800, "white": 16300 } - }, - - /* Phase One: color matrices borrowed from Adobe DNG Converter, black/white levels tested on actual raw files. - Note: the dcraw decoder makes black level subtraction and various corrections to the raw values based on - metadata embedded in the IIQ format, so what we see here is the result after that, ie black level is 0, - and white level is typically at or close to 65535. However sensors vary a bit and can be noisy around clip - so we cut away 0.05 stop from top down to 63300 to be a bit conservative. */ - { // quality A - "make_model": [ "Phase One P40+", "Phase One IQ140", "Leaf Credo 40", "Phase One P65+", "Phase One IQ160", "Leaf Credo 60", "Phase One IQ260" ], - "dcraw_matrix": [ 8035,435,-962,-6001,13872,2320,-1159,3065,5434 ], - "ranges": { "black": 0, "white": 63300 } - }, - { // quality A - "make_model": [ "Phase One IQ180", "Leaf Credo 80", "Phase One IQ280" ], - "dcraw_matrix": [ 6294,686,-712,-5435,13417,2211,-1006,2435,5042 ], - "ranges": { "black": 0, "white": 63300 } - }, - { // quality A - "make_model": [ "Phase One P20", "Phase One P20+", "Phase One P25", "Phase One P25+" ], - "dcraw_matrix": [ 2905,732,-237,-8135,16626,1476,-3038,4253,7517 ], - "ranges": { "black": 0, "white": 63300 } - }, - { // quality A - "make_model": [ "Phase One P21", "Phase One P21+" ], - "dcraw_matrix": [ 6516,-2050,-507,-8217,16703,1479,-3492,4741,8489 ], - "ranges": { "black": 0, "white": 63300 } - }, - { // quality A - "make_model": [ "Phase One P30", "Phase One P30+"], - "dcraw_matrix": [ 4516,-244,-36,-7020,14976,2174,-3206,4670,7087 ], - "ranges": { "black": 0, "white": 63300 } - }, - { // quality A - "make_model": [ "Phase One P45", "Phase One P45+" ], - "dcraw_matrix": [ 5053,-24,-117,-5685,14077,1703,-2619,4491,5850 ], - "ranges": { "black": 0, "white": 63300 } - }, - { // quality X, matrix taken from H5D-50c which has the same sensor, probably with the same CFA. Color looks good to the eye with files tested. - "make_model": [ "Phase One IQ250", "Leaf Credo 50" ], - "dcraw_matrix": [ 4932, -835, 141, -4878, 11868, 3437, -1138, 1961, 7067 ], - "ranges": { "black": 0, "white": 64400 } // CMOS sensor, we dare to set white level a bit higher than for the more varying Phase One CCDs - }, - - { // Quality A for tested CFV, the other models have the same sensor (16 megapixel square sensor) - "make_model": [ "Hasselblad V96C", "Hasselblad CFV", "Hasselblad CFV-II" ], - "dcraw_matrix": [ 8519, -3260, -280, -5081, 13459, 1738, -1449, 2960, 7809 ] // borrowed from Adobe's DNG converter - }, - { // Quality A for tested CF-22, the other models have the same sensor - "make_model": [ "Hasselblad CF-22", "Hasselblad CF-22MS", "Hasselblad CFH-22", "Hasselblad H3D-22", "Hasselblad H3DII-22" ], - "dcraw_matrix": [ 8519, -3260, -280, -5081, 13459, 1738, -1449, 2960, 7809 ] // borrowed from Adobe's DNG converter - }, - { // Quality A for tested H3D-31, the other models have the same sensor - "make_model": [ "Hasselblad H3D-31", "Hasselblad H3DII-31", "Hasselblad H4D-31" ], - "dcraw_matrix": [ 5458, -1448, 145, -4479, 12338, 2401, -1659, 3086, 6710 ] // borrowed from Adobe's DNG converter - }, - { // Quality A for tested CFV-39, the other models have the same sensor. Small filter differences may exist so some might do better with a slightly different profile - "make_model": [ "Hasselblad CF-39", "Hasselblad CF-39MS", "Hasselblad CFH-39", "Hasselblad CFV-39", "Hasselblad H3D-39", "Hasselblad H3DII-39", "Hasselblad H3DII-39MS" ], - "dcraw_matrix": [ 3857, 452, -46, -6008, 14477, 1596, -2627, 4481, 5718 ] // borrowed from Adobe's DNG converter - }, - { // Quality A for tested CFV-50, the other models have the same sensor - "make_model": [ "Hasselblad CFV-50", "Hasselblad H3DII-50", "Hasselblad H3DII-50MS", "Hasselblad H4D-50", "Hasselblad H4D-50MS", "Hasselblad H4D-200MS", "Hasselblad H5D-50", "Hasselblad H5D-50MS", "Hasselblad H5D-200MS" ], - "dcraw_matrix": [ 5656, -659, -346, -3923, 12306, 1791, -1602, 3509, 5442 ] // borrowed from Adobe's DNG converter - }, - { // Quality A - "make_model": [ "Hasselblad H4D-40", "Hasselblad H5D-40" ], - "dcraw_matrix": [ 6159, -1402, -177, -5439, 12762, 3007, -955, 2200, 7104 ] // borrowed from Adobe's DNG converter - }, - { // Quality A for tested H4D-60, the other models have the same sensor - "make_model": [ "Hasselblad H4D-60", "Hasselblad H5D-60" ], - "dcraw_matrix": [ 9662, -684, -279, -4903, 12293, 2950, -344, 1669, 6024 ] // borrowed from Adobe's DNG converter - }, - { // Quality A - "make_model": [ "Hasselblad H5D-50c", "Hasselblad CFV-50c" ], - "dcraw_matrix": [ 4932, -835, 141, -4878, 11868, 3437, -1138, 1961, 7067 ] - }, - - // dummy test entry to test the parser and show the format with all entries active - { - "make_model": "DummyMake DummyModel", - "dcraw_matrix": [ 7530,-1942,-255,-4318,11390,3362,-926,1694,7649 ], - "raw_crop": [ 10, 20, 4000, 3000 ], - "masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ], - "ranges": { - "aperture_scaling": [ - { "aperture": 1.2, "scale_factor": 1.1 }, - { "aperture": 1.4, "scale_factor": 1.08 } - ], - "black": [ - { "iso": 100 , "levels": [ 10, 20, 10, 20 ] }, - { "iso": [100, 200] , "levels": [ 30, 40, 30 ] }, - { "iso": 3200, "levels": [ 50, 60, 50, 60 ] } - ], - "white": [ - { "iso": 100 , "levels": [ 10000, 11000, 10000, 11000 ] }, - { "iso": 3200, "levels": [ 11000, 11000, 10000, 11000 ] } - ], - "white_max": 16383 - } - } -]} +/* + + DO NOT EDIT THIS FILE! + + All changes made here will be lost on software update. + If you want to add custom values or changes existing ones, + create a "camconst.json" file next to your personal "options" file. + Its values will then override and/or complete the ones of this file. + + If you add values for your own camera and are okay to share them with + RawTherapee's community, please drop a link on the user's forum + + IMPORTANT: + ---------- + + 1. If you set the dcraw matrix in your user file for an already existing entry + in RT's file (same camera, same model), your values will replace RT's ones. + 2. If you set the Black level(s) values in your user file for an already existing + entry in RT's file, your values will replace RT's ones, even if RT's ones are + more complete and/or detailed. You might want to copy/paste RT's levels first + (if provided) to your user's file and complete/modify it. + + Same for the White level(s), independently from the Black level(s). + + +---------------------------------------------------------------------------------- + + +This file is in JSON format and contains camera constants which RawTherapee uses +when parsing raw files. + +Raw files themselves unfortunately do not contain all information needed for making +a raw conversion, typically color response information and black/white levels are +missing. That's why this file is needed. + +It's read once during startup, so if the file is updated you need to restart +RawTherapee in order to take effect. The file is not intended for modification by +the casual user, but advanced users can add missing camera information to this file. +If you do so please report at http://code.google.com/p/rawtherapee/issues so we can +extend the distributed version of this file so your provided camera information +becomes available to all. + +RawTherapee uses DCRAW as the raw format parser. DCRAW contains hard-coded camera +constants, but not for all cameras and not always accurate information. For example +DCRAW only support one white level, while some cameras have different white levels +per channel and per ISO. If a camera is not listed in this file the constants from +DCRAW will be used, if listed here this information will override any constants in +DCRAW (if any). + +Some cameras may only have partial information here, for example if the raw file +itself contains a color matrix it's not entered here. A camera whose black level +is measured on special pixels in the raw file should only have white levels here +etc. + +Examples: + + { + // make and model separated with single space, must match make + // and model as provided by dcraw (case-insensitive). + "make_model": "ManufacturerA ModelB", + // ColorMatrix with D65 Calibration Illuminant, in dcraw format + "dcraw_matrix": [ 7530, -1942, -255, -4318, 11390, 3362, -926, 1694, 7649 ], + // black level (or black offset if a base black is already extracted from exif by Dcraw, see Panasonic, resent Nikon ) + // and white level same for all colors at all ISOs + "ranges": { "black": 10, "white": 1000 }, + // crop away masked sensor borders, 10 pixels left, 20 pixels top, resulting image width/height 4000x3000 + // instead of width/height you can write a negative number which specifies how much of right/bottom border + that should be removed but keep in mind that sometimes after converting to DNG the borders are already + cropped so the "negative number" way is not totally safe. + "raw_crop": [ 10, 20, 4000, 3000 ], + // Almost same as MaskedAreas DNG tag, used for black level measuring here two areas defined + "masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ], + The difference here is the meaning of the numbers which here are expressing the absolute distance (in pixels) + of each side of each rectangular "masked area" from the top and left side of the sensor + - the first number is the distance of the top edge from the sensor's top + - the second is the distance of the left side from the sensor's left + - the third is the distance of the bottom side from the sensor's top + - the fourth is the distance of the right side from the sensor's left + }, + + { + "make_model": "ManufacturerA ModelB", + "dcraw_matrix": [ 7530,-1942,-255,-4318,11390,3362,-926,1694,7649 ], + // black and white levels per ISO per channel + // this example only two ISOs, normally the list should be more populated. + // When RawTherapee asks for black/white levels for a specific ISO the closest + // match is picked. + "ranges": { + "black": [ + { "iso": 100, "levels": 10 }, // here only one level, same level for all channels + { "iso": 3200, "levels": [ 50, 60, 50 ] } // 3 levels, G2 same as G1 + ], + "white": [ + { "iso": 100, "levels": [ 10000, 11000, 10000, 12000 ] }, // 4 levels, G1 and G2 different + { "iso": 3200, "levels": [ 11000, 11000, 10000, 12000 ] } + ] + } + } + +How to measure white levels: +---------------------------- + +Dcraw which provides the default values to RawTherapee often provides too high +white levels, and only provides a single value regardless of color channel, ISO +or aperture. If you open an image with a large clipped area and that is +rendered in a pink/magenta color rather than white it usually means that the +white level constant is too high. You can fix this by adjusting the +"Raw White Point" in the raw tab inside RawTherapee, or permanently fix it by +measuring and providing a more exact white level in camconst.json so +RawTherapee gets to know from start where the camera actually clips. + +Providing a complete and detailed white-level profile can be a quite large +and complicated effort. As an alternative you can provide a simpler profile. +We suggest one of the following alternatives in rising difficulty (and +generally diminishing return): + +A) Provide a single white-level value measured on the native ISO (base ISO). + For many cameras this will actually be complete information, those that + don't vary on channel, ISO or aperture. +B) Check through all ISOs and if there are differences in white level provide + an array with white level per ISO. +C) In addition to ISO, check for aperture scaling and add that. +D) In addition to ISO and aperture scaling check for color channel + differences and add that. + +Doing A) is often better than nothing, as dcraw's default is often too high. +B) can also be worthwhile for some cameras (or else you'll get pink highlights +for some ISOs), while C) and D) can generally be seen as fine-tuning. + +Here follows a guide how to measure white levels (clipping levels): + +Shoot with your camera into a bright light source, such as a lamp, and make +sure the shutter speed is long enough to get overexposure (we want +clipping!). Preferably overexpose lightly, say 1 or 2 stops if you can. The +reason for this is that some cameras with fuzzy white levels may look less +fuzzy than they actually are if over-exposure is heavy. + +Use f/5.6 or smaller aperture (=larger f-number) to avoid any raw scaling +the camera might have for large apertures. + +Open the file in a raw analyzer such as Rawdigger and check the pixel values +for the clipped areas (if you are using Rawdigger, make sure you have disabled +"subtract black" in preferences or else sample values can be wrong). In this +stage we always look at white level before black level subtraction! White +levels can be different on color channel (R, G1, B, G2, note the two greens, +most often both green channels have the same white level though) and vary +depending on ISO setting, so if you want to provide a complete profile make +one shoot for each ISO (even 1/3 steps, so yes it can be quite a lot of +pictures to shoot and check). + +In addition, many cameras scale the raw values for large apertures. It's +generally not that important to cover this, but if you want to extract most +out of the camera you should cover this too. Then you need to shoot with a +wide aperture lens (ideally the widest available from the manufacturer) and +test each aperture (1/3 steps) from the widest (say f/1.2) until the camera +stops scaling the raw values (usually f/2.8 or f/4.0). If the camera also +have ISO scaling you need to shoot at these different ISOs to detect any +differences in scaling, there can be a bit of variation. If you don't have +access to the widest lens available for the system (say only an f/1.8 lens +instead of an f/1.2) it can still be valuable to have the values down to +what you can provide. Brands known to have models that have aperture scaling +of white levels include Canon and Nikon. Note that if white levels are not +scaled the camera may have raw scaling anyway (Sony for example), but as +such scaling will not affect raw decoding we don't need to care about that. + +PROVIDE CONSERVATIVE VALUES. Most cameras have a little noise at the white +level, and some can have a lot. In your raw analyzer, move around and look at +the values in the clipped areas to get a sense of the variation, and/or look +at the histogram. While it's common to with very little variation, say only ++/-2 units, some can have +/-500 or more (some may have different variation +depending on ISO). There can also be camera-to-camera variation. + +If the white level is set too high RawTherapee will not think the pixels are +clipped and you can get discoloured highlights (usually pink), this is what +we want to avoid. If white level is set too low RawTherapee will clip early, ie +you lose a little highlight detail, but the color is rendered correctly and +highlight reconstruction can work properly, so this is not as bad. This is why +we want conservative values. + +By conservative values we mean that if you see a white level of most often +15760 and occassionally 15759 (ie very small variation of white level which +is a common case), you set the white level around 40-80 14bit units below or +10-20 12bit units. Say at 15700 in this example, or 4080 instead of 4095 for +12bit raws. This way we get a little margin from noise and camera variation. +Since sensor raw values are linear you lose in this example log2(1-50/15760) = +-0.005 stop of detail, ie irrelevant. Thus it's better to provide RawTherapee +with knowledge where the image clips rather than keeping that last 0.005 stop +of highlight information and risking that clipping will not be detected +properly. + +It is very usual for white level to be a bell distribution instead of a candle +when the camera applies long exposure noise reduction by subtracting a black frame +and/or when the system is destabilized due to temperature. Some models have +always a bell distribution at WL. +If you have a fuzzy white level look at the linear histogram; you will probably +see a normal/gaussian distribution (bell shape) noise peak at clipping and +probably also a peak at a hard raw data clip level usually at or close to a +power of two - 1, such as 4095 or 16383. Then you pick a value just before the +bell shape rises, ie to the left of the bell meaning that you cut away the +whole fuzzy noise peak. If a little of the starting edge of the noise will be +included it's not harmful, but 99% of it should be above. +This would mean that it's better to measure white level on long exposure/ high temp +raws but since this if difficult and time consuming we choose to measure on normal +raws and cover the abnormalities whith the conservative WL values. + +If you have used Adobe's DNG Converter and analyzed it's output you may have +noticed that it's very conservative regarding white levels, ie it cuts away +quite a lot from the top. While we also recommend to be conservative, you can +generally be a little bit less so than Adobe's DNG Converter. RawTherapee is +meant to max out what you can get from your camera, and the white levels should +mirror that, within reason. + +The aperture scaling feature is meant to raise the white level to not miss out +on highlight detail when the camera has scaled the raw values (and thus +raised white levels). Many cameras do this, but not all, and can only do it +for lenses that report aperture to the camera (ie you see it in the EXIF +data). Providing proper aperture scaling values is a bit more advanced task, +so if you are unsure we recommend to skip that part. + +Beware that the raw format may have a ceiling so that it clips scaled values, +for example the Canon 5D mark II maxes out at 16383 which happens at f/1.8 +for ISOs with the white level at 15750, but for ISO160 when the white level +is 12800 it does not max out. If there is such a raw limit it must also be +provided ("ranges":"white_max"). Usually you will not need a margin on +white_max as it clips there as a result of an in-camera math operation. + +Note that aperture scaling can be quite small, for the 5D mark II it's only +0.2 stop down to f/1.2 and then it can be discussed if it's worthwhile to care. +The "worst" cameras scale about 0.6 stops though, and then it's more +valuable to compensate. If you skip aperture scaling RawTherapee will clip the +files a little bit too early and you miss that last fraction of highlight +detail, but you get no processing problems. Setting unconservative scale +factors can on the other hand cause a too high whitelevel and break highlight +processing, so be careful. + +Scaling can vary sligthly depending on ISO (if white levels vary) so make +sure to provide conservative scalings so regardless of ISO you don't get a +too high white level. We recommend to keep a small margin here also +white levels, ie 0.5% lower or so. For example if base (not conservative!) +white level is 15750 and the scaled is 16221 we have a scaling factor of +16221/15750=1.0299 ie +2.9% we set the factor to 1.025 to keep a margin. +The abnormal cases are already covered by setting conservative per ISO White levels. + +The scale factor you provide here is applied on the white level before black +level subtraction (if any), ie directly on the white level value you provide in +the camconst.json file. Black level (if provided) is not scaled. Please report +to us if you come across a camera which scales black levels, then we can add +that as an option. Usually the camera applies an offset to shift back the +black level to the standard level after scaling. + +If RawTherapee doesn't find an entry for the aperture used in the image, it +will pick the closest above. Ie if the apertures 1.0 and 2.0 is in the table +and the image has aperture 1.2, it will pick scaling for 2.0, even if 1.0 is +the closer aperture. The reason for always checking the closest above is that +we rather get a bit too low white level than too high, as discussed before. + +Some cameras have different white levels on different color channels. When +this is the case the difference is often so small so you can just provide a +single value instead, ie a conservative value based on the lowest clipping. + +What we know at the time of writing about different brands/models (not +complete info): + + - Canon CR2: typically same clipping per channel, but significant variations + on ISO and aperture. Maxes out at 16383, black level measured on masked + black pixels, ie don't provide that. + - Nikon NEF: sometimes different clipping per color (most often negligible + though). Will do aperture and ISO scaling, but often to a lesser extent + than Canon files, ie not as much to gain. + - Sony ARW2: no scaling. Generally black level around 512, and white level + 16350 and to be conservative say 16300. + +Note that some raw formats may go through a certain amount of pre-processing +based on meta data, such as curve and levels adjustments and various +calibrations. The Phase One IIQ is one example, and this means that if you +look at the data in a raw analyzer such as RawDigger it may perform a +different type of preprocessing than RawTherapee's loader does, and you may +end up providing incompatible black/white levels. + +You can use RawTherapee for analysis too, it's safer as you are using it's +own raw decoder but it's not as user-friendly: enable verbose mode in options +so you get output on the console. When you load a file you will see a message +of current black and white levels and if they came from dcraw or camconst.json. +If you're adjusting an existing camconst.json value you can just read what it is in +the file and not need to enable verbose output. + +Reset exposure sliders to neutral, and zoom in on a large clipped highlight. +Move around the mouse pointer within, it should show stable 100% on R G B. If +so, the white level is not too high, it could however be too low. To test that, +go to the raw tab and adjust the "whitepoint linear correction factor", reduce +it until one of the channels is no longer 100%, and then increase in steps of +0.01 until all are 100 again. Usually you play around in the range 0.90 to +0.99, ie a very small adjustment. When you've found this factor you should +apply it on the old white level to find a new larger one. As RT's "whitepoint +linear correction factor" work after blacklevel subtraction and camconst.json +want values without it we need to do some math: + +BL = black level (typically something near 0, 256, 512, 1024 or 2048 find it in the + verbose output or if available in camconst.json) +F = whitepoint linear correction factor you just found out (typically in the + range 0.90 to 0.99 if you need to increase white level, 1.01 to 1.10 if + decrease) +oldWL = old white level, found in verbose output or in camconst.json if + available. + +new white level = BL + (oldWL - BL) / F + +Note that if black level is 0 which it is for many cameras, the formula +simplifies to: new white level = oldWL / F. + +Here's an example from a Canon 1000D: black level is 256, old white level is +3651, whitepoint correction factor becomes 0.90, then new white level is +256 + (3651 - 256) / 0.9 = 4028. + +If your camera have different black levels per channel use the one which +yields the smallest white level (can be the largest or smallest, test!). + +This new white level you then enter in your camconst.json file. The same +procedure can be used if the white level is too high, ie if you see pink +highlights, then increase the correction factor above 1.0 until you just start +seeing stable 100% on all channels, you use the same formula to calculate the +new smaller white level. + +About black levels: +------------------- + +Unlike for white levels it's much more common that black levels can be +derived from the format. Either it's simply 0 (typical for old Nikon cameras, +newer Nikons (year2013-14) have a BL at around 150 12bit or 600/768 14bit ), +or it can be derived from masked pixels (typical for Canon cameras) or otherwise +be extracted from some tag. +Some formats have built-in subtraction information and are pre-processed by DCRaw +to end up at a black level of zero(Phase One's IIQ). +For Panasonic raws beginning from Dcraw v9.21 Dcraw/RT reads base BL from exif data +(tags 0x001c BlackLevelRed, 0x001d BlackLevelGreen, 0x001e BlackLevelBlue)and we +define in "ranges": { "black": the needed offset of around 15. The (total) BL RT displays is base+offset +In all, you typically should not care about the black level in camconst.json, +any information that can be derived from the raw file itself should not be specified in camconst.json! +Sony's ARW2 is one of the few exceptions (with single black level around 512, or 800 for RX10/100 models), +but DCraw generally has good constants for these already. + +Currently we have chosen not to provide any guide how to measure black levels +as we don't think it will be a common task (it's also more difficult to do +than measure white levels). If you experience a black level issue it's more +likely due to a format parsing bug which should be fixed in DCRaw and/or +RawTherapee's raw format parser. + +How does a black level issue look? If the image has a color cast and is +possibly duller than normal it's likely that black levels are off. The color +cast is typically stronger in darker colors but it can be hard to see, it's +more often experienced as a cast over the whole image. + +*/ +{"camera_constants": [ + +/* + +When adding camera constants please set a quality level so we know the status for future updates + +Quality A: complete information, no need to add more, to the best of our knowledge +Quality B: not complete, but very little to gain from adding more +Quality C: complementing with additional information would provide significant gain +Quality X: unknown, ie we knowing to little about the camera properties to know if + we have enough info or not. + +*/ + + { // quality A + "make_model": "Canon EOS 5D Mark II", + "dcraw_matrix": [ 4716,603,-830,-7798,15474,2480,-1496,1937,6651 ], + "ranges": { + // black levels are read from raw masked pixels + // white levels are same for all colors, but vary on ISO + "white": [ + { "iso": 50, "levels": 15600 }, // typical: 15760 + { "iso": 100, "levels": 15600 }, + { "iso": 125, "levels": 15600 }, + { "iso": 160, "levels": 12700 }, + { "iso": 200, "levels": 15600 }, + { "iso": 250, "levels": 15600 }, + { "iso": 320, "levels": 12700 }, // typical: 12810 + { "iso": 400, "levels": 15600 }, + { "iso": 500, "levels": 15600 }, + { "iso": 640, "levels": 12700 }, + { "iso": 800, "levels": 15600 }, + { "iso": 1000, "levels": 15600 }, + { "iso": 1250, "levels": 12700 }, + { "iso": 1600, "levels": 15600 }, + { "iso": 2000, "levels": 15600 }, + { "iso": 2500, "levels": 15600 }, + { "iso": 3200, "levels": 15600 }, + { "iso": 4000, "levels": 15600 }, + { "iso": 5000, "levels": 15600 }, + { "iso": 6400, "levels": 16200 }, // typical: 16383 + { "iso": 12800, "levels": 16200 }, + { "iso": 25600, "levels": 16200 } + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for and f/1.0 (had no lenses to test with), but the + typical 15700 white level maxes out at "white_max" for f/1.8 and below anyway. */ + { "aperture": 1.2, "scale_factor": 1.100 }, // guessed by relative 5DIII data + { "aperture": 1.4, "scale_factor": 1.077 }, + { "aperture": 1.6, "scale_factor": 1.054 }, + { "aperture": 1.8, "scale_factor": 1.039 }, + { "aperture": 2.0, "scale_factor": 1.031 }, + { "aperture": 2.2, "scale_factor": 1.021 }, + { "aperture": 2.5, "scale_factor": 1.016 }, + { "aperture": 2.8, "scale_factor": 1.010 }, + { "aperture": 3.2, "scale_factor": 1.004 }, + { "aperture": 3.5, "scale_factor": 1.003 } + ] + } + }, + { // quality A, + "make_model": "Canon EOS 5D Mark III", + "dcraw_matrix": [ 6722,-635,-963,-4287,12460,2028,-908,2162,5668 ], + "ranges": { + // black levels are read from raw masked pixels + // white levels are same for all colors, but vary on ISO + "white": [ + { "iso": [ 50, 100, 125, 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000, 12800, 16000, 20000 ], "levels": 15180 }, // typical: 15282 + { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000 ], "levels": 13200 }, // typical: 13306 + { "iso": [ 25600, 32000, 40000, 51200, 102400 ], "levels": 16200 } + ], + "white_max": 16383, + "aperture_scaling": [ + { "aperture": 1.2, "scale_factor": 1.130 }, + { "aperture": 1.4, "scale_factor": 1.090 }, + { "aperture": 1.6, "scale_factor": 1.065 }, + { "aperture": 1.8, "scale_factor": 1.040 }, + { "aperture": 2.0, "scale_factor": 1.025 }, + { "aperture": 2.2, "scale_factor": 1.020 }, + { "aperture": 2.5, "scale_factor": 1.015 }, + { "aperture": 2.8, "scale_factor": 1.010 }, + { "aperture": 3.2, "scale_factor": 1.005 }, + { "aperture": 3.5, "scale_factor": 1.002 } + ] + } + }, + + { // Quality C, intermediate ISO samples missing but safely guessed, aperture scaling measures missing + "make_model": [ "Canon EOS 5DS R", "Canon EOS 5DS" ], + // "dcraw_matrix": [ 6848,-1661,-221,-3904,10931,3434,-470,1251,6039 ], // DNG_V9.0 A + "dcraw_matrix": [ 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 ], // DNG_V9.0 D65 + "raw_crop": [ 192, 96, 8696, 5800 ], // 800, 300, 7500, 4700 - 160,64,8730x5800 - sensor 8896x5920 top64, left160, official crop left196, top100, right 8883, bottom 5891, 8688X5792 + "masked_areas": [ 100, 40, 5892, 158 ], // left out 40 first columns from calculations because possibly the BL is still imbalanced there + "ranges": { + "white": [ + { "iso": 100, "levels": 14650 }, // typical 14733 + { "iso": [ 160, 320, 640, 1250, 2500, 5000 ], "levels": 15280 }, // typical 15383 + { "iso": [ 125, 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200 ], "levels": 15280 }, // typical 15383 + { "iso": [ 4000, 6400, 8000, 10000, 12800, 16000, 20000, 25600 ], "levels": 15100 } // clippings at R 15200-15280, G1,G2,B 15360-15390 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: scale factors measured for f/2.8 only, */ + { "aperture": 1.4, "scale_factor": 1.055 }, // guessed + { "aperture": 1.6, "scale_factor": 1.034 }, // guessed + { "aperture": 1.8, "scale_factor": 1.021 }, // guessed + { "aperture": 2.0, "scale_factor": 1.013 }, // guessed + { "aperture": 2.2, "scale_factor": 1.008 }, // guessed + { "aperture": 2.5, "scale_factor": 1.005 }, // guessed + { "aperture": 2.8, "scale_factor": 1.003 }, // 14783/14733 + { "aperture": 3.2, "scale_factor": 1.000 }, // guessed + { "aperture": 3.5, "scale_factor": 1.000 } + ] + } + }, + + { // Quality A, some missing scaling factors are safelly guessed - most samples by sfink16 at RT forums + "make_model": "Canon EOS 6D", + "dcraw_matrix": [ 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 ], + "ranges": { + "white": [ + { "iso": [ 50, 100, 125, 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000, 12800, 16000, 25600 ], "levels": 15180 }, // typical 15283 + { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000, 20000 ], "levels": 13100 }, // typical 13225 + { "iso": [ 51200, 102400 ], "levels": 16280 } // typical 16383 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.0 (had no lenses to test with), but the + ISO 160-320... 12650 white levels maxes out at "white_max" for f/1.2 and below anyway. */ + { "aperture": 1.2, "scale_factor": 1.130 }, // from histogramm 1 gap in every 7 levels + { "aperture": 1.4, "scale_factor": 1.090 }, // histogram 3 gaps in every 32 levels + { "aperture": 1.6, "scale_factor": 1.060 }, // 16213/15283 + { "aperture": 1.8, "scale_factor": 1.040 }, // guessed + { "aperture": 2.0, "scale_factor": 1.030 }, // 15800/15283 + { "aperture": 2.2, "scale_factor": 1.020 }, // guessed + { "aperture": 2.5, "scale_factor": 1.015 }, // 15541/15283 + { "aperture": 2.8, "scale_factor": 1.010 }, // 15437/15283 + { "aperture": 3.2, "scale_factor": 1.005 }, // 15361/15283 + { "aperture": 3.5, "scale_factor": 1.000 } // no sample + ] + } + }, + { // Quality A, ISO and aperture WL data by CharlyW at RawTherapee forums, missing samples safely guessed + "make_model": "Canon EOS 7D", + "dcraw_matrix": [ 5962,-171,-732,-4189,12307,2099,-911,1981,6304 ], // Colin Walker + // "dcraw_matrix": [ 6844,-996,-856,-3876,11761,2396,-593,1772,6198 ], // dcraw + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13584 + { "iso": [ 160, 320, 640, 1250, 2500 ], "levels": 12550 }, // typical 12650 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 5000, 6400, 12800 ], "levels": 15200 } // typical 15304 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (no lenses to test with), but the + typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.250 }, // guessed + { "aperture": 1.6, "scale_factor": 1.150 }, // guessed + { "aperture": 1.8, "scale_factor": 1.110 }, // 15196/13584 + { "aperture": 2.0, "scale_factor": 1.080 }, // 14734/13584 + { "aperture": 2.2, "scale_factor": 1.050 }, // 14386/13584 + { "aperture": 2.5, "scale_factor": 1.040 }, // 14272/13584 + { "aperture": 2.8, "scale_factor": 1.030 }, // 14042/13584 + { "aperture": 3.2, "scale_factor": 1.015 }, // guessed + { "aperture": 3.5, "scale_factor": 1.000 } // guessed negligible + ] + } + }, + + { // Quality b, ISO and aperture WL data by ..... at RawTherapee forums, missing samples safely guessed + "make_model": "Canon EOS 550D", + "dcraw_matrix": [ 6941,-1164,-857,-3825,11597,2534,-416,1540,6039 ], // dcraw 550d + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13584 + { "iso": [ 160, 320, 640, 1250, 2500 ], "levels": 12550 }, // typical 12650 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 5000, 6400, 12800 ], "levels": 15200 } // typical 15304 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (no lenses to test with), but the + typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.250 }, // guessed + { "aperture": 1.6, "scale_factor": 1.150 }, // guessed + { "aperture": 1.8, "scale_factor": 1.110 }, // 15196/13584 + { "aperture": 2.0, "scale_factor": 1.080 }, // 14734/13584 + { "aperture": 2.2, "scale_factor": 1.050 }, // 14386/13584 + { "aperture": 2.5, "scale_factor": 1.040 }, // 14272/13584 + { "aperture": 2.8, "scale_factor": 1.030 }, // 14042/13584 + { "aperture": 3.2, "scale_factor": 1.015 }, // guessed + { "aperture": 3.5, "scale_factor": 1.000 } // guessed negligible + ] + } + }, + { // Quality A, f/1.6 aperture scale factor missing but safely guessed, ISO and aperture data by charlyw at RT forums + "make_model": "Canon EOS 7D Mark II", + "dcraw_matrix": [ 7268,-1082,-969,-4186,11839,2663,-825,2029,5839 ], // dng_v8.7 d65 + // "dcraw_matrix": [ 6285,-147,-821,-4080,11695,2714,-1045,2459,5497 ], // DXO D50 + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13500 }, // typical 13583 - LENR 13550 + { "iso": [ 160, 320, 640, 1250, 2500, 5000 ], "levels": 12500 }, // typical 12559 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000 ], "levels": 15200 }, // typical 15303 - LENR 15270,15260,15240,15220, + { "iso": [ 6400, 8000, 10000, 12800, 16000, 20000, 25600 ], "levels": 15100 }, // typical G1,G2 15303, R,B = 15430 LENR 15200 .. 15100 + { "iso": 51200, "levels": 16300 } // typical 16383 red 16371 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.6, f/1.0 (had no lenses to test with) */ + { "aperture": 1.4, "scale_factor": 1.200 }, // 15100/12277 exif + { "aperture": 1.6, "scale_factor": 1.100 }, // guessed + { "aperture": 1.8, "scale_factor": 1.050 }, // 14372/13583 - 13283 + { "aperture": 2.0, "scale_factor": 1.030 }, // 14034/13583 - 12973 + { "aperture": 2.2, "scale_factor": 1.015 }, // 13808/13583 - 12766 + { "aperture": 2.5, "scale_factor": 1.007 }, // 13696/13583 - 12662 + { "aperture": 2.8, "scale_factor": 1.007 }, // 13696/13583 - 12663 + { "aperture": 3.2, "scale_factor": 1.000 }, // 13583/13583 - 12559 + { "aperture": 3.5, "scale_factor": 1.000 } + ] + } + }, + + { // Quality A - ISO and aperture WL data by Ilias at Avclub gr forums + "make_model": "Canon EOS 40D", + "dcraw_matrix": [ 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 ], + "raw_crop": [ 30, 18, 3908, 2602 ], + "masked_areas": [ 20, 2, 2616, 20 ], + "ranges": { + "white": [ + { "iso": 100, "levels": 13700 }, // typical 13825 + { "iso": [ 125, 250, 500, 1000, 3200 ], "levels": 16280 }, // typical 16383 + { "iso": [ 160, 320, 640 ], "levels": 12600 }, // typical 12744 + { "iso": [ 200, 400 ], "levels": 16100 }, // typical 16224 + { "iso": 800, "levels": 15900 }, // gaussian histogram 15900-16224 + { "iso": 1600, "levels": 14900 }, // gaussian histogram 14900-15750 + { "iso": 1250, "levels": 11900 } // gaussian histogram 11900-12500 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the + typical 12700 white levels maxes out at "white_max" for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.265 }, // 16142/12744 + { "aperture": 1.6, "scale_factor": 1.145 }, // 15872/13825 + { "aperture": 1.8, "scale_factor": 1.090 }, // 15103/13825 + { "aperture": 2.0, "scale_factor": 1.035 }, // 14334/13825 + { "aperture": 2.2, "scale_factor": 1.005 }, // 13950/13825 + { "aperture": 2.5, "scale_factor": 1.000 } // 13825/13825 + ] + } + }, + { // Quality A, ISO and aperture WL data by Ayshih at Magic Lantern forums + "make_model": "Canon EOS 50D", + "dcraw_matrix": [ 4920,616,-593,-6493,13964,2784,-1774,3178,7005 ], + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13300 }, // typical 13432 + { "iso": [ 160, 320, 640, 1250 ], "levels": 12700 }, // typical 12790-12810 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 2500, 3200 ], "levels": 15630 }, // typical 15763-15733 + { "iso": [ 6400, 12800 ], "levels": 16200 } // typical 16383 + ], + "white_max": 16383, + "aperture_scaling": [ + { "aperture": 1.4, "scale_factor": 1.270 }, + { "aperture": 1.6, "scale_factor": 1.150 }, + { "aperture": 1.8, "scale_factor": 1.090 }, + { "aperture": 2.0, "scale_factor": 1.040 }, + { "aperture": 2.2, "scale_factor": 1.020 }, + { "aperture": 2.5, "scale_factor": 1.010 }, + { "aperture": 2.8, "scale_factor": 1.000 }, + { "aperture": 3.2, "scale_factor": 1.000 } + ] + } + }, + { // Quality A, ISO and aperture WL data copyed from Shalrath's 60D data at RawTherapee forums + "make_model": "Canon EOS 60Da", + "dcraw_matrix": [ 17492,-7240,-2023,-1791,10323,1701,-186,1329,5406 ], // 60Da dng d65 + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 + { "iso": [ 160, 320, 640, 1250, 2500 ], "levels": 12550 }, // typical 12650 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 5000, 6400, 12800 ], "levels": 15200 } // typical 15304 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the + typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.300 }, // gaps 81of301 + { "aperture": 1.6, "scale_factor": 1.200 }, + { "aperture": 1.8, "scale_factor": 1.140 }, + { "aperture": 2.0, "scale_factor": 1.080 }, // gaps 1of11 + { "aperture": 2.2, "scale_factor": 1.060 }, + { "aperture": 2.5, "scale_factor": 1.050 }, + { "aperture": 2.8, "scale_factor": 1.030 }, + { "aperture": 3.2, "scale_factor": 1.015 }, + { "aperture": 3.5, "scale_factor": 1.000 } // no sample but it would be negligible + ] + } + }, + { // Quality A, ISO and aperture WL data by Shalrath at RawTherapee forums + "make_model": "Canon EOS 60D", + "dcraw_matrix": [ 6719,-994,-925,-4408,12426,2211,-887,2129,6051 ], + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 + { "iso": [ 160, 320, 640, 1250, 2500 ], "levels": 12550 }, // typical 12650 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 5000, 6400, 12800 ], "levels": 15200 } // typical 15304 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the + typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.300 }, // gaps 81of301 + { "aperture": 1.6, "scale_factor": 1.200 }, + { "aperture": 1.8, "scale_factor": 1.140 }, + { "aperture": 2.0, "scale_factor": 1.080 }, // gaps 1of11 + { "aperture": 2.2, "scale_factor": 1.060 }, + { "aperture": 2.5, "scale_factor": 1.050 }, + { "aperture": 2.8, "scale_factor": 1.030 }, + { "aperture": 3.2, "scale_factor": 1.015 }, + { "aperture": 3.5, "scale_factor": 1.000 } // no sample but it would be negligible + ] + } + }, + { // Quality B, more aperture scale factors needed + "make_model": "Canon EOS 70D", + "dcraw_matrix": [ 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 ], // DNG D65 + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 + { "iso": [ 160, 320, 640, 1250, 2500, 5000 ], "levels": 12450 }, // typical 12559 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000, 10000 ], "levels": 15200 }, // typical 15303 - ISO 8000-10000 guessed + { "iso": [ 12800, 25600 ], "levels": 16200 } // typical 16383 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but even with the + 12500 white levels nearly maxes out for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.240 }, // guessed + { "aperture": 1.6, "scale_factor": 1.160 }, // guessed + { "aperture": 1.8, "scale_factor": 1.110 }, // 31of35 + { "aperture": 2.0, "scale_factor": 1.060 }, // guessed + { "aperture": 2.2, "scale_factor": 1.030 }, // guessed + { "aperture": 2.5, "scale_factor": 1.015 }, // guessed + { "aperture": 2.8, "scale_factor": 1.008 }, // 15432/15303 + { "aperture": 3.2, "scale_factor": 1.000 }, + { "aperture": 3.5, "scale_factor": 1.000 } + ] + } + }, + + { // Quality b, scaling factors missing but guessed safely + "make_model": [ "Canon EOS 1200D", "Canon EOS Rebel T5", "Canon EOS 600D", "Canon EOS Rebel T3i" ], + "dcraw_matrix": [ 6461,-907,-882,-4300,12184,2378,-819,1944,5931 ], // dcp D65 colormatrix2 + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 + { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000 ], "levels": 12550 }, // typical 12650 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000, 12800 ], "levels": 15200 } // typical 15303 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the + typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.290 }, // guessed from 60D data + { "aperture": 1.6, "scale_factor": 1.190 }, // guessed + { "aperture": 1.8, "scale_factor": 1.140 }, // guessed + { "aperture": 2.0, "scale_factor": 1.090 }, // 12293/11222 = 1.095 + { "aperture": 2.2, "scale_factor": 1.060 }, // 11971/11222 = 1.066 + { "aperture": 2.5, "scale_factor": 1.050 }, // guessed + { "aperture": 2.8, "scale_factor": 1.030 }, // iso100: 14042/13584=1.0336 - iso200 15820/15303 = 1.0348 + { "aperture": 3.2, "scale_factor": 1.000 }, // + { "aperture": 3.5, "scale_factor": 1.000 } // + ] + } + }, + + { // Quality A, only one scaling factor missing and guessed safely + "make_model": [ "Canon EOS 650D", "Canon EOS Rebel T4i" ], + "dcraw_matrix": [ 6602,-841,-939,-4472,12458,2247,-975,2039,6148 ], + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 + { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000 ], "levels": 12550 }, // typical 12650 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000 ], "levels": 15200 }, // typical 15303 + { "iso": [ 12800, 25600 ], "levels": 16200 } // typical 16383 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the + typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.200 }, // 16332/13583 + { "aperture": 1.6, "scale_factor": 1.080 }, // guessed + { "aperture": 1.8, "scale_factor": 1.055 }, // 14372/13583 + { "aperture": 2.0, "scale_factor": 1.030 }, // 14034/13583 + { "aperture": 2.2, "scale_factor": 1.025 }, // 13921/13583 + { "aperture": 2.5, "scale_factor": 1.020 }, // + { "aperture": 2.8, "scale_factor": 1.000 }, // + { "aperture": 3.2, "scale_factor": 1.000 }, // + { "aperture": 3.5, "scale_factor": 1.000 } // + ] + } + }, + + { // Quality C, aperture scale factors and intermediate ISOs missing but safely guessed + "make_model": [ "Canon EOS 750D", "Canon EOS Rebel T6i", "Canon EOS 760D", "Canon EOS Rebel T6s" ], + "dcraw_matrix": [ 6362,-823,-847,-4426,12109,2616,-743,1857,5635 ], // dng_v9.0 d65 + "raw_crop": [ 72, 34, 6024, 4022 ], // full size 6096x4056, official crop 84,46,6083,4045 + "masked_areas": [ 40, 16, 4000, 54 ], + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13300 }, // typical 13583 + { "iso": [ 160, 320, 640, 1250, 2500, 5000 ], "levels": 12500 }, // typical 12600 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000 ], "levels": 15200 }, // typical 15303 + { "iso": [ 6400, 8000, 10000, 12800, 16000, 20000 ], "levels": 15100 }, // typical 15303 + { "iso": 25600, "levels": 16300 } // typical 16383 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: all scale factors are guessed to be same as 7DII */ + { "aperture": 1.4, "scale_factor": 1.200 }, // guessed + { "aperture": 1.6, "scale_factor": 1.100 }, // guessed + { "aperture": 1.8, "scale_factor": 1.050 }, // guessed + { "aperture": 2.0, "scale_factor": 1.030 }, // guessed + { "aperture": 2.2, "scale_factor": 1.015 }, // guessed + { "aperture": 2.5, "scale_factor": 1.007 }, // guessed + { "aperture": 2.8, "scale_factor": 1.007 }, // guessed + { "aperture": 3.2, "scale_factor": 1.000 }, // guessed + { "aperture": 3.5, "scale_factor": 1.000 } + ] + } + }, + + { // Quality B, missing scaling factors are guessed safely from 650D relative data + "make_model": "Canon EOS M", + "dcraw_matrix": [ 6602,-841,-939,-4472,12458,2247,-975,2039,6148 ], + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 + { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000 ], "levels": 12550 }, // typical 12650 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000 ], "levels": 15200 }, // typical 15303 + { "iso": [ 12800, 25600 ], "levels": 16200 } // typical 16383 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the + typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.200 }, // guessed + { "aperture": 1.6, "scale_factor": 1.080 }, // guessed + { "aperture": 1.8, "scale_factor": 1.055 }, // guessed + { "aperture": 2.0, "scale_factor": 1.030 }, // 15821/15303 + { "aperture": 2.2, "scale_factor": 1.025 }, // 15691/15303 + { "aperture": 2.5, "scale_factor": 1.020 }, // 12947/12650 + { "aperture": 2.8, "scale_factor": 1.000 }, // + { "aperture": 3.2, "scale_factor": 1.000 }, // + { "aperture": 3.5, "scale_factor": 1.000 } // + ] + } + }, + + { // Quality C, White Levels not properly indicated, aperture scaling..missing scaling factors are guessed + "make_model": "Canon EOS M3", + "dcraw_matrix": [ 6362,-823,-847,-4426,12109,2616,-743,1857,5635 ], // DNG_V8.8 D65 + "raw_crop": [ 72, 34, 6024, 4022 ], // full size 6096x4056, official crop 84,46,6083,4045 + "masked_areas": [ 40, 16, 4000, 54 ], + "ranges": { + "white": [ + { "iso": [ 100, 125, 160 ], "levels": 16300 }, // 16383 + { "iso": [ 320, 640, 1250, 2500, 5000, 10000 ], "levels": 12600 }, // 12632..14500 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000 ], "levels": 15000 }, // 15095, 15488 + { "iso": [ 6400, 8000, 12800, 25600 ], "levels": 16200 } // 16383 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: need for more data to properly fill all scale factors */ + { "aperture": 1.4, "scale_factor": 1.200 }, // guessed + { "aperture": 1.6, "scale_factor": 1.080 }, // guessed + { "aperture": 1.8, "scale_factor": 1.055 }, // guessed + { "aperture": 2.0, "scale_factor": 1.030 }, // guessed + { "aperture": 2.2, "scale_factor": 1.025 }, // guessed + { "aperture": 2.5, "scale_factor": 1.020 }, // guessed + { "aperture": 2.8, "scale_factor": 1.000 }, // + { "aperture": 3.2, "scale_factor": 1.000 }, // + { "aperture": 3.5, "scale_factor": 1.000 } // + ] + } + }, + { /* Quality B, needs a way to auto apply 3/2 or 4/3 crops (read exif tags ..) to work better with auto distortion, + for the moment just comment-uncomment the desired raw crop */ + "make_model": "Canon PowerShot G1 X Mark II", + "dcraw_matrix": [ 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 ], // D65 matrix from adobe dcp + // "raw_crop": [ 80, 50, 4400, 3316 ], // full frame 4480x3366 borders 80,50 - much shade in corners, no/wrong auto distortion + // "raw_crop": [ 104, 144, 4360, 3128 ], // Mixed best average frame, width is 4352 from 3/2, height 3120 from 4/3 - auto distortion does not work correctly + // "raw_crop": [ 200, 144, 4168, 3128 ], // Optional official 4/3 frame 4160x3120, 4pix borders, Left Border 204-4, Top Border 148-4 + "raw_crop": [ 104, 252, 4360, 2912 ], // Default official 3/2 frame 4352X2904, 4pix borders, Left Border 108-4, Top border 256-4 + "masked_areas": [ 148, 2, 3340, 78 ], + "ranges": { "white": 16300 } + }, + + { // Quality B, + "make_model": "Canon PowerShot G7 X", + "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 ], // DNG_V8.7 D65 + // "raw_crop": [ 116, 24, 5504, 3680 ], // Sensor size 5632x3710. Largest useful frame 120-5616X28-3702 = 5504x3682, 4pix RTborders, Left Border 120-4, Top border 28-4 + "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 + "masked_areas": [ 40, 4, 3680, 76 ], + "ranges": { "white": 4080 } + }, + + { // Quality B, + "make_model": "Canon PowerShot G3 X", + "dcraw_matrix": [ 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 ], // DNG_V9.1.1 D65 + "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 + "masked_areas": [ 40, 4, 3680, 76 ], + "ranges": { "white": 16300 } + }, + + { // Quality A, changes for raw crop which is wrong (larger) in Dcraw + "make_model": "Canon PowerShot S120", + "dcraw_matrix": [ 6961,-1685,-695,-4625,12945,1836,-1114,2152,5518 ], + "raw_crop": [ 120, 30, 4024, 3030 ], + "masked_areas": [ 32, 2, 3028, 80 ], + "ranges": { "white": 4050 } + }, + + { // Quality A, changes for raw crop which is optimistic in Dcraw + "make_model": "Canon PowerShot G12", + "dcraw_matrix": [ 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 ], + // "raw_crop": [ 62, 18, 3666, 2748 ],// max usable + "raw_crop": [ 68, 20, 3656, 2744 ],// equal to official Canon frame, 72,24,3719,2759 = 3648x2736 + "masked_areas": [ 24, 40, 2770, 44 ],// as declared in maker data + "ranges": { "white": 4080 } // + }, + + { // Quality B + "make_model": "Canon PowerShot SX60 HS", + "dcraw_matrix": [ 13161,-5451,-1344,-1989,10654,1531,-47,1271,4955 ], // DNG_V8.7 D65 + "raw_crop": [ 120, 34, 4616, 3464 ], // full raw 4768x3516, Usable 96,16,4672,3498 - Canon official 4608x3456 left 124 top 38, + "masked_areas": [ 20, 2, 3480, 80 ], + "ranges": { "white": 4050 } // nominal 4080-4093 + }, + + { // Quality A + "make_model": "FUJIFILM S1", + "dcraw_matrix": [ 12297,-4882,-1202,-2106,10691,1623,-88,1312,4790 ] // DNG_v8.5 D65 + }, + + { // Quality B, + "make_model": [ "FUJIFILM X100S", "FUJIFILM X100T" ], + "dcraw_matrix": [ 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 ], // DNG_v8.7 D65 + "ranges": { "white": 16100 } + }, + + { // Quality B + "make_model": "FUJIFILM X-A2", + "dcraw_matrix": [ 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 ], // DNG D65 + "ranges": { "white": 4050 } + }, + { // Quality B + "make_model": [ "FUJIFILM X-T1", "FUJIFILM X-T10", "FUJIFILM X-E2" ], + "dcraw_matrix": [ 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 ], // DNG D65 +// "dcraw_matrix": [ 9289,-3279,-632,-3539,11137,2758,-1049,1950,6544 ], // X-RITE D55 + "ranges": { "white": 16100 } + }, + + { // Quality B + "make_model": "FUJIFILM X30", + "dcraw_matrix": [ 12328,-5256,-1144,-4469,12927,1675,-87,1291,4351 ], // DNG_v8.7 D65 + "ranges": { "white": 4040 } + }, + + { // Quality B + "make_model": "FUJIFILM XQ2", + "dcraw_matrix": [ 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 ], // DNG_v8.8 D65 + "ranges": { "white": 4040 } + }, + { // Quality A + "make_model": [ "Nikon 1 V3", "Nikon 1 J4" ], // Same format + "dcraw_matrix": [ 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 ], // matrix from DNG_v8.5 d65 + // "dcraw_matrix": [ 5306,-1066,-469,-3865,11189,3076,-399,1341,5120 ], // matrix dXo D50, + "ranges": { "white": 4080 } // Black is auto extracted from exif, lower WL to 4080 from 4095 due to some non linearity detected at raw highlights + }, + + { // Quality B, + "make_model": "Nikon 1 J5", // + "dcraw_matrix": [ 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 ], // DNG_v9.1 D65 + // "dcraw_matrix": [ 7651,-2102,-751,-3299,11101,1651,-1011,2242,5770 ], // matrix from ICC converted to Dcraw format XYZ on ImagingResource stillife sample + "ranges": { + "white": [ + { "iso": [ 160, 200 ], "levels": 4000 }, // typical G1/G2 4020-4028, R/B 4088 + { "iso": [ 400, 800, 1600, 3200 ], "levels": 4000 }, // g1/g2 4030-4040, r/b 4088 + { "iso": [ 6400, 12800 ], "levels": 4080 } // 4090 + ] + } + }, + + { // Quality A, + "make_model": "Nikon 1 S2", // + "dcraw_matrix": [ 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 ], // matrix from DNG_v8.5 d65 + "ranges": { "white": 4080 } // BL autodetected from exif + }, + + { // quality B, lacks aperture and ISO scaling, known to exist, but little to gain as the levels are so close to white_max + "make_model": "Nikon D7000", + "dcraw_matrix": [ 7530,-1942,-255,-4318,11390,3362,-926,1694,7649 ], // matrix provided by Tanveer(tsk1979) + "ranges": { + // measured at ISO 100. ISO differences not measured, but known to exist + "white": [ 16370, 15760, 16370 ], // typical R 16383, G 15778, B 16383 + "white_max": 16383 + // aperture scaling not measured, but known to exist, at f/1.8 the G channels hits white_max + } + }, + + { // Quality B, aperture scaling used to scale WL at safer levels + "make_model": "Nikon D5300", + "dcraw_matrix": [ 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 ], // adobe dng_v8.8 d65 + "ranges": { "white": 16300 } // attention.. WL value is for 14bit files, has to be 4070 for 12bit files. WL typical 16383 set to 16300 for safety + }, + + { // Quality B, aperture scaling used to scale WL at safer levels + "make_model": "Nikon D5500", + "dcraw_matrix": [ 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 ], // adobe dng_v9.0 d65 + "ranges": { "white": 16300 } // attention.. WL value is for 14bit files, has to be 4070 for 12bit files. WL typical 16383 set to 16300 for safety + }, + + { // Quality B, color matrix from DNG_v9.0 instead of internal Dcraw_v9.25_r1.475, + "make_model": "Nikon D7200", + "dcraw_matrix": [ 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 ], // adobe dng_v9.0 d65 + "ranges": { "white": 16300 } // attention.. WL values are for 14bit files, has to be WL4070 for 12bit files. WL typical 16383 set to 16300 for safety, + }, + + { // quality B, samples by joachip at RT forums, are measures at long exposures with LongExposureNoiseReduction + // aperture scaling known to exist, but little to gain as the levels are so close to white_max + "make_model": "Nikon D600", + "dcraw_matrix": [ 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 ], // dcp d65 + // "raw_crop": [ 0, 0, 6034, 4028 ], // dcraw + "ranges": { + "white": [ + { "iso": [ 50, 100 ], "levels": [ 15800, 15800, 15350 ] }, // typical G1/G2/R 15879, B 15395-15670 lowered to 15800, 15350, 3969 B3917 + { "iso": [ 200, 400, 800 ], "levels": [ 16300, 15700, 16300 ] }, // 15878, 16383 + { "iso": 1000, "levels": [ 16300, 16100, 16300 ] }, // 12bit lossless r4095, 3981-10, b4041- 12bit lossy r,g1,g2 3961 - b3917, + { "iso": 1600, "levels": [ 16300, 16100, 16300 ] }, // 16145-165, 16383 + { "iso": [ 3200, 6400, 12800, 25600 ], "levels": [ 16300, 16300, 16300 ] } // 16383 + ], + "white_max": 16383 + } + }, + { // quality B, lacks WL measures at intermediate ISOs (160-250-320 ..) and measures at long exposures with LongExposureNoiseReduction + // aperture scaling known to exist, but little to gain as the levels are so close to white_max + "make_model": "Nikon D610", + "dcraw_matrix": [ 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 ], // dcp d65 + "raw_crop": [ 0, 0, 6034, 4028 ], // Dcraw has no raw crop for D610 + "ranges": { + "white": [ + { "iso": [ 50, 100 ], "levels": [ 15800, 15700, 15800 ] }, // typical G1/G2 15778, R/B 15879 lowered to 15700, 15800 for possible WL distribution under LENR + { "iso": [ 200, 400, 800 ], "levels": [ 16300, 15700, 16300 ] }, // 15878, 16383 + { "iso": 1600, "levels": [ 16300, 16100, 16300 ] }, // 16145-165, 16383 + { "iso": [ 3200, 6400, 12800, 25600 ], "levels": [ 16300, 16300, 16300 ] } // 16383 + ], + "white_max": 16383 + } + }, + + { // quality B; Data from RusselCottrell at RT forums. sensor is not uniform + "make_model": "Nikon D700", + "dcraw_matrix": [ 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 ], + "ranges": { "white": 15750 } // Non linearities start at 15750 (hi ISOs) 15850 (low ISOs) with long exposures (>2sec) and LENR ON .. nominal 15892 + // white 15750 is correct for 14bit files, 12 bit files need white level at 3900 + }, + + { // Quality B, + "make_model": "Nikon D750", + "dcraw_matrix": [ 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 ], // adobe dcp d65 DNGv8.7 + "ranges": { "white": 16300 } // attention.. WL values are for 14bit files, has to be WL4070 for 12bit files. WL typical 16383 set to 16300 for safety + }, + + { // quality B; Data from RussellCottrell at RT forums. Largest aperture scale factor is 1.013, about 1/50th of a stop + "make_model": "Nikon D800E", + "dcraw_matrix": [ 7866,-2108,-555,-4869,12483,2681,-1176,2069,7501 ], // D800/D800E from dcraw.c + "ranges": { + "white": [ + { "iso": [ 100, 125, 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250 ], "levels": [ 16300, 15700, 16300 ] }, // 15779-15781 + { "iso": [ 1600 ], "levels": 16000 }, // 16085-16113 + { "iso": [ 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 16300 } // 16383 + ] + } + }, + { // quality B, WL set at 16300 from nominal 16380 for possible non linearities with LENR + "make_model": "Nikon D810", + "dcraw_matrix": [ 9369,-3195,-791,-4488,12430,2301,-893,1796,6872 ], // dcp_v8.6 d65 + "raw_crop": [ 0, 0, 7380, 4928 ], // Official raw crop 7380x4928, + "ranges": { "white": 16300 } // attention WL 16300 is for 14bit raws and has to be 4070 for 12 bit raws. Typical WL at 16383 + }, + { // Quality b, 16Mp and 64Mp raw frames + "make_model": "OLYMPUS E-M5MarkII", + "dcraw_matrix": [ 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 ], // DNG_v8.8 D65 + "raw_crop": [ 0, 0, -6, -6 ], // largest valid, full 64Mp 9280x6938, official crop 0 0 9216 6912 - safe 5755 + "ranges": { + "white": [ + { "iso": [ 100, 200 ], "levels": 3950 }, // normal 4080-4095, HR Dpreview 4047, IR 3956 + { "iso": [ 400, 800, 1600, 3200 ], "levels": 4070 }, // 4070-4095 + { "iso": [ 6400, 12800, 25600 ], "levels": 4040 } // 4000-4095 + ] + } + }, + + { // Quality b, crop correction + "make_model": "OLYMPUS E-M10", + "dcraw_matrix": [ 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 ], + "raw_crop": [ 0, 0, 4624, 3472 ], // largest valid - full frame is 4640x3472 +// "raw_crop": [ 4, 4, 4616, 3464 ], // olympus jpeg crop 8, 8, 4608, 3456 + "ranges": { "white": 4080 } + }, + { // Quality A, white level correction + "make_model": "OLYMPUS E-PM2", + "dcraw_matrix": [ 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 ], + "ranges": { "white": 4040 } // nominal 4056 + }, + + { // Quality B, with long exposure noise reduction White Level gets WL-BL = around 256_12bit levels less + "make_model": "OLYMPUS E-PL7", + "dcraw_matrix": [ 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 ], // DNG_V8.7 D65 + "ranges": { "white": 4080 } // nominal 4093 + }, + + { // Quality B, per ISO WL measures missing + "make_model": "OLYMPUS SH-2", + "dcraw_matrix": [ 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 ], // DNG_V9.1 D65 + "ranges": { "white": 4050 } // safe for worst case detected, nominal is 4093 + }, + + /* since Dcraw_v9.21 Panasonic base BL is read from exif (tags 0x001c BlackLevelRed15 is BL offstet. + Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset, 0x001d BlackLevelGreen, 0x001e BlackLevelBlue + and we define here the needed offset of around 15. The total BL is base+offset */ + + { // Quality B, CameraPhone, some samples are missing but has the same sensor as FZ1000 .. + "make_model": "Panasonic DMC-CM1", + "dcraw_matrix": [ 8770,-3194,-820,-2871,11281,1803,-513,1552,4434 ], // dcp_v8.7 d65 + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": 80, "levels": 3600 }, // exif:3277 distribution peak at 3700 up to +/- 100 + { "iso": [ 100, 125, 200, 400, 800, 1600 ], "levels": 4050 }, // exif 4095 distribution 4050-4095 + { "iso": [ 3200, 6400, 12600, 25600 ], "levels": 4080 } // exif 4095 distribution 4080-4095 + ] + } + }, + + { // Quality A , replicated from rawimage.cc + "make_model": "Panasonic DMC-FZ150", + "dcraw_matrix": [ 10435,-3208,-72,-2293,10506,2067,-486,1725,4682 ], // RT, copy from custom dcp d55 + "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + }, + + { // Quality Β, + "make_model": [ "Panasonic DMC-FZ300", "Panasonic DMC-FZ330" ], + "dcraw_matrix": [ 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 ], // DNG-V9.1.1 + "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + }, + + { // Quality A, samples by helices at Rt forums + "make_model": [ "Panasonic DMC-FZ1000", "Leica V-LUX (Typ 114)" ], + "dcraw_matrix": [ 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 ], // dcp_v8.6 d65 + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": 80, "levels": 3600 }, // exif:3277 distribution peak at 3700 up to +/- 100 + { "iso": [ 100, 125, 200, 400, 800, 1600 ], "levels": 4050 }, // exif 4095 distribution 4050-4095 + { "iso": [ 3200, 6400, 12600, 25600 ], "levels": 4080 } // exif 4095 distribution 4080-4095 + ] + } + }, + + { // Quality A + "make_model": [ "Panasonic DMC-LF1", "Leica C (Typ 112)" ], + "dcraw_matrix": [ 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 ], + "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + }, + { // Quality A + "make_model": [ "Panasonic DMC-TZ60", "Panasonic DMC-TZ61", "Panasonic DMC-ZS40", "Panasonic DMC-ZS41" ], + "dcraw_matrix": [ 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 ], // matrix from Adobe dcp v8.4 + "raw_crop": [ 8, 8, -8, -8 ], // crop according to exif 4896 X 3672 plus 4 pixels borders. RT's frame gets smaller than Dcraw but works better with auto distortion + "ranges": { "black": 14, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + }, + { // Quality B, + "make_model": [ "Panasonic DMC-TZ70", "Panasonic DMC-TZ71", "Panasonic DMC-ZS50", "Panasonic DMC-ZS51" ], + "dcraw_matrix": [ 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 ], // DNG_V8.8 D65 + "raw_crop": [ 4, 4, -4, -4 ], // full raw 4/3 4144x3016 8,8,3008,4008 = 4000X3000. RT's frame gets smaller than Dcraw but works better with auto distortion + "ranges": { "black": 14, "white": 4050 } // 12+1+1 is BL offset + }, + + // Panasonic DMC-FZ150,G10,G1,G2,G3,G5,GF1,GF2,GF3 are included as overwrites of the same items of rawimage.cc to test the Dcraw9.21 patch + + { // Quality A, Replicated from rawimage.cc + "make_model": [ "Panasonic DMC-G10", "Panasonic DMC-G2" ], + "dcraw_matrix": [ 8310,-1811,-960,-4941,12990,2151,-1378,2468,6860 ], // Colin Walker + "ranges": { + "black": 15, // 15 is black offset, Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:3967 distribution peak at 3967 +/- up to 50 + { "iso": [ 1600, 3200, 6400 ], "levels": 4060 } // exif 3967, histogram peak 4095 and distribution down to 4070 + ] + } + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-G1", + "dcraw_matrix": [ 7477,-1615,-651,-5016,12769,2506,-1380,2475,7240 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:4095 distribution peak at 3977 +/- up to 50 + { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 + ] + } + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-G3", + "dcraw_matrix": [ 6051,-1406,-671,-4015,11505,2868,-1654,2667,6219 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": 4060 } // exif:4095 normal distribution 4080-4095, 4070-4095 on long exposure NR + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-G5", + "dcraw_matrix": [ 7122,-2092,-419,-4643,11769,3283,-1363,2413,5944 ], // RT + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": 4060 } // exif:4095 normal distribution 4080-4095, 4070-4095 on long exposure NR + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-GF1", + "dcraw_matrix": [ 7863,-2080,-668,-4623,12331,2578,-1020,2066,7266 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:4095 distribution peak at 3977 +/- up to 50 + { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 + ] + } + }, + + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-GF2", + "dcraw_matrix": [ 7694,-1791,-745,-4917,12818,2332,-1221,2322,7197 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": 4050 } // exif:4095 normal distribution 4080-4095, 4050-4095 on long exposure NR + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-GF3", + "dcraw_matrix": [ 8074,-1846,-861,-5026,12999,2239,-1320,2375,7422 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": 4050 } // exif:4095 normal distribution 4080-4095, 4050-4095 on long exposure NR + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-GH1", + "dcraw_matrix": [ 6360,-1557,-375,-4201,11504,3086,-1378,2518,5843 ], // Colin Walker + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 3930 }, // exif:4095 distribution peak at 3982 +/- up to 50 + { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 + ] + } + }, + { // Quality A, Replicated from rawimage.cc + "make_model": "Panasonic DMC-GH2", + // "dcraw_matrix": [ 6855,-1765,-456,-4223,11600,2996,-1450,2602,5761 ], // Colin Walker - disabled due to problems with underwater + "dcraw_matrix": [ 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 ], // Dcraw d65 + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": [ 100, 200, 400, 800 ], "levels": 3930 }, // exif:4095 distribution peak at 3982 +/- up to 50 + { "iso": [ 1600, 3200, 6400, 12800 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 + ] + } + }, + + { // Quality B, variable WL + "make_model": "Panasonic DMC-GH3", + "dcraw_matrix": [ 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 ], // dcp d65 + "ranges": { + "black": 16, // 16 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": 125, "levels": 3500 }, // gaussian 3600-4095 + { "iso": [ 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 + ] + } + }, + + { // Quality B, some ISO WLevels are safely guessed + "make_model": "Panasonic DMC-GH4", + "dcraw_matrix": [ 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 ], // dng_v8.5 d65 + "ranges": { + "black": 16, // 16 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": 100, "levels": 2700 }, // gaussian center at 2870-2920 range +/- 150, exif 2111 + { "iso": 125, "levels": 3100 }, // guessed + { "iso": [ 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 + ] + } + }, + + { // Quality A, + "make_model": "Panasonic DMC-GM1", + "dcraw_matrix": [ 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 ], + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": 125, "levels": 3100 }, // bell shape 3150-3650 - exif 2616 + { "iso": 160, "levels": 3600 }, // guessed from relative GX7 data + { "iso": [ 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 + ] + } + }, + + { // Quality B, uncertainty about ISO100 WL + "make_model": "Panasonic DMC-GM5", + "dcraw_matrix": [ 8238,-3244,-679,-3921,11814,2384,-836,2022,5852 ], // dng_v8.7 d65 + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": 100, "levels": 2800 }, // bell shape 2850-3250 - exif 2111 + { "iso": [ 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 + ] + } + }, + { // Quality A, + "make_model": [ "Panasonic DMC-GX7", "Panasonic DMC-GF7" ], + "dcraw_matrix": [ 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 ], + "ranges": { + "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": 125, "levels": 3100 }, + { "iso": 160, "levels": 3600 }, + { "iso": [ 200, 250, 320, 400,500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 + ] + } + }, + + { // Quality A, + "make_model": [ "Panasonic DMC-G7", "Panasonic DMC-G70" ], + "dcraw_matrix": [ 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 ],// DNG_v9.1 D65 + // "dcraw_matrix": [ 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 ], // LX100, DNG_V8.7 d65 + "ranges": { + "black": 16, // 16 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": 100, "levels": 2300 }, // gaussian 2300-2700 exif_linearitylimit 2111 + { "iso": 125, "levels": 3180 }, // gaussian 3200-3600 exif_linearitylimit 2626 + { "iso": [ 160, 200, 250, 320, 400,500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 + ] + } + }, + { // Quality B, + "make_model": "Panasonic DMC-GX8", + "dcraw_matrix": [ 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 ], // DNG_v9.1.1 D65 + "ranges": { + "black": 15, // 16 is BL offstet. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "white": [ + { "iso": 100, "levels": 2300 }, // gaussian 2300-2700 exif_linearitylimit 2111 + { "iso": 125, "levels": 3180 }, // guessed gaussian 3200-3600 exif_linearitylimit 2626 + { "iso": [ 160, 200, 250, 320, 400,500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 + ] + } + }, + { // Quality B, uncertainty about ISO 100 WL + "make_model": [ "Panasonic DMC-LX100", "Leica D-LUX (Typ 109)" ], + "dcraw_matrix": [ 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 ], // DNG_V8.7 d65 + // "dcraw_matrix": [ 6538,-1614,-549,-5475,13096,2646,-1780,2799,5612 ], // calculated from DxO D50 + "ranges": { + "black": 15, // 15 is BL offset calculated from exif data. + "white": [ + { "iso": 100, "levels": 2300 }, // gaussian 2400-2700 exif_linearitylimit 2111 + { "iso": [ 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 + ] + } + }, + + { // Quality B, intermediate ISOs info missing + "make_model": [ "RICOH PENTAX K-3", "PENTAX K-3" ], + "dcraw_matrix": [ 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 ], // adobe dcp d65 +// "dcraw_matrix": [ 8542,-2581,-1144,-3995,12301,1881,863,1514,5755 ], // pentax DNG +// "dcraw_matrix": [ 6464,-1574,-422,-5324,12712,2934,-1129,1724,6900 ], // DxO + "raw_crop": [ 10, 4, 6028, 4024 ], + "ranges": { + "white": [ + { "iso": 100, "levels": 16310 }, // 16317 or 16350 + { "iso": 200, "levels": 16120 }, // 16254 or 16125 + { "iso": 400, "levels": 15860 }, // 16125 or 15868 + { "iso": 800, "levels": 15360 }, // 15868 or 15364-15370 + { "iso": [ 1600, 3200, 6400, 12800, 25600, 51200 ], "levels": 16300 } // 16383 - pentax dng tag is 15868-15350 + ] + } + }, + + { // Quality B, intermediate ISOs info missing, spread due to blackframe subtraction guessed to be around 10levels + "make_model": "PENTAX K10D", + "dcraw_matrix": [ 9566,-2863,-803,-7170,15172,2112,-818,803,9705 ], // adobe DNG d65 + // "raw_crop": [ 0, 0, 3888, 2608 ], + "ranges": { + "white": [ + { "iso": 100, "levels": 4080 }, // R,G1,B = 4095 G2= 4087 + { "iso": 200, "levels": 4080 }, // R,G1,B = 4093-94 G2= 4087or94 + { "iso": 400, "levels": 4080 }, // R,G1 = 4093-94, B=4094 G2= 4087or93or94 + { "iso": 800, "levels": 4070 }, // R,G1 = 4091-4093, B=4091-92 G2= 4078or82or84-86 + { "iso": [ 1600, 3200 ], "levels": 4060 } // 4067or4073-76 + ] + } + }, + + { // Quality B, corrections for raw crop vs Dcraw9.21, matched to Samsung's default + "make_model": "Samsung NX mini", + "dcraw_matrix": [ 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 ], // dng 8.6 d65 + "raw_crop": [ 128, 36, 5480, 3656 ], // jpeg 5472x3648 - full raw: 5664 x 3710 - Samsung's official crop: 132, 40, 5604, 3688 + "ranges": { "white": 4030 } // double clipping point for each channel at a) 4095 and b) bell distribution with peak at 4038 .. used the conservative one + }, + { // Quality A, Conflict with "Samsung NX30" in Dcraw_v9.21_r1.414, frame corrections and color data + "make_model": "Samsung NX3000", + "dcraw_matrix": [ 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 ], // DNG_v8.7.1 D65 + "raw_crop": [ 92, 38, 5480, 3656 ] // jpeg 5472x3648 - full raw: 5600 x 3714 - Samsung's official crop: 96, 42, 5568, 3690 + }, + + { // Quality B, RT normally use the embedded data with DNGs but because various DNG use different color matrix adobe_coeff setting is used in dcraw.cc to always use the data from camconst.json for NX1 + "make_model": [ "Samsung NX1", "Samsung NX500" ], + "dcraw_matrix": [ 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 ], // DNG_v8.7 D65 + // "dcraw_matrix": [ 13298,-6099,-296,-5243,16153,-1235,-508,1220,7758 ], // DNG_v8.7 Standard Light A + // "dcraw_matrix": [ 9598,-3268,-634,-5678,14795,824,-1255,2675,4523 ], // SAMSUNG DNG CONVERTER + "ranges": { + "white": [ + { "iso": 100, "levels": 16000 }, // typical 16084, LE 16120 and 16383, LENR 16280 + { "iso": [ 200, 400, 800, 1600, 3200, 6400, 12800 ], "levels": 16300 }, // 16383 + { "iso": [ 25600, 51200 ], "levels": 16300 } // 16383 + ] + } + }, + + { // Quality c, corrections for frame size, black and white levels not declared properly + "make_model": "Sigma SD9", + "dcraw_matrix": [ 14996,-3468,-1425,5576,3642,972,1761,3773,3720 ], // experimental calculated from sun0.icc data + "ranges": { "black": 0, "white": 16383 },// black is already subtracted by dcraw, white copied from x3dump data + "raw_crop": [ 20, 8, -18, -12 ] + }, + { // Quality c, corrections for frame size, black level not declared properly + "make_model": "Sigma SD10", + "dcraw_matrix": [ 12555,-1865,-1125,5093,4120,867,1929,3810,3507 ], // experimental calculated from .icc data + "ranges": { "black": 0, "white": 16383 },// black is already subtracted by dcraw, white copied from x3dump data + // "raw_crop": [ 0, 0, -0, -0 ] + "raw_crop": [ 20, 8, -18, -12 ] + }, + { // Quality c, corrections for frame size, black and white levels not declared properly + "make_model": "Sigma SD14", + "dcraw_matrix": [ 16411,-4764,-2383,8110,2603,-645,3135,3878,1984 ], // experimental inverted icc wp12 - build with BL=15 + // "dcraw_matrix": [ 13804,-4156,-1896,6917,1909,-431,2768,2989,1741 ], // experimental inverted icc wp10 - build with BL=15 + "ranges": { "black": 0, "white": 16383 },// peripheral black stripes give BL around 37 + "raw_crop": [ 0, 0, -0, -0 ] + // "raw_crop": [ 18, 12, 2652, 1768 ] + }, + + { // Quality c, correction for frame width + "make_model": "Sigma SD1", + "dcraw_matrix": [ 5270,42,-814,3737,5506,124,1112,9714,4510 ], // experimental from icm 1.04477,-0.74838,1.01617, -0.54028,2.52690,-3.83257, 0.54869,-0.69556,3.73746 + "ranges": { "black": 16, "white": 4070 },// BL is 16 or 31, should be measured at the horizontal black stripe at the top + "raw_crop": [ 12, 52, -110, -8 ] + }, + { // Quality C, correction for frame width, color matrix investigated .. + "make_model": "Sigma SD1 Merrill", + "dcraw_matrix": [ 7211,-1577,-769,4996,3428,440,2717,7117,4699 ], // experimental inverted icc cloudy8140 d65 + // "dcraw_matrix": [ 5666,139,-892,3780,5428,270,1366,9757,4526 ], // experimental inverted icc sunny8161 + // "dcraw_matrix": [ 10288,-2449,-1718,8976,1868,-1608,7011,5039,-249 ], // experimental inverted icc tungsten8130 wp11 + // "dcraw_matrix": [ 5864,679,-1491,2963,7635,-919,-640,13738,2790 ], // experimental inverted icc sunny8160 + // "dcraw_matrix": [ 14032,-2231,-1016,-5263,14816,170,-112,183,9113 ], // hardcoded + "ranges": { "black": 16, "white": 4070 }, // BL is 16 or 31, should be measured at the horizontal black stripe at the top + "raw_crop": [ 12, 52, -110, -8 ] // for small size all numbers/2 + }, + { // Quality C, correction for frame width, color matrix guessed .. + "make_model": [ "Sigma DP1 Merrill", "Sigma DP2 Merrill", "Sigma DP3 Merrill" ], + "dcraw_matrix": [ 5666,139,-892,3780,5428,270,1366,9757,4526 ], // copy fron SD1 Merrill icc cloudy8140 d65 + "ranges": { "black": 16, "white": 4070 }, // BL is 16 or 31, should be measured at the horizontal black stripe at the bottom + "raw_crop": [ 12, 0, -110, -62 ] // for small size all numbers/2 + }, + + + { // Quality A, correction for color matrix from Colin Walker's d50 to dng d65 + "make_model": "Sony NEX-C3", + // "dcraw_matrix": [ 5130,-1055,-269,-4473,11797,3050,-701,1310,7121 ], // Colin walker's d50 kept for possible consistency issues + "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], + "ranges": { "black": 512, "white": 16300 } + }, + + { // Quality A, correction for frame width + "make_model": "Sony NEX-5N", + "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], + "raw_crop": [ 0, 0, 4920, 3276 ], + "ranges": { "black": 512, "white": 16300 } + }, + { // Quality A, + "make_model": "Sony ILCA-77M2", + "dcraw_matrix": [ 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 ], // adobe dcp d65 + "raw_crop": [ 0, 0, 6024, 4024 ], + "ranges": { "black": 512, "white": 16300 } + }, + + { // Quality A, correction for frame width + "make_model": [ "Sony ILCE-3000", "Sony ILCE-3500", "Sony ILCE-5000", "Sony ILCE-QX1" ], + "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], // adobe dcp d65 + "ranges": { "black": 512, "white": 16300 }, + "raw_crop": [ 0, 0, 5476, 3656 ] + }, + { // Quality A, + "make_model": "Sony ILCE-5100", + "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], // adobe dcp d65 + "raw_crop": [ 0, 0, 6024, 4024 ], + "ranges": { "black": 512, "white": 16300 } + }, + { // Quality A + "make_model": "Sony ILCE-6000", + "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], // adobe dcp d65 + "raw_crop": [ 0, 0, 6024, 4024 ], + "ranges": { "black": 512, "white": 16300 } + }, + { // Quality A + "make_model": "Sony ILCE-7M2", + "dcraw_matrix": [ 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 ], // DNGv8.7.1 + "ranges": { "black": 512, "white": 16300 } + }, + { // Quality A, correction for frame width + "make_model": "Sony ILCE-7R", + "dcraw_matrix": [ 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 ], + "raw_crop": [ 0, 0, 7372, 4920 ], + "ranges": { "black": 512, "white": 16300 } + }, + + { // Quality B, correction for frame width, crop modes not covered + "make_model": "Sony ILCE-7RM2", + "dcraw_matrix": [ 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 ], // DNG_v9.1.1 D65 + "raw_crop": [ 0, 0, 7964, 5320 ], // full raw frame 8000x5320 - 36 rightmost columns are garbage + "ranges": { "black": 512, "white": 16300 } + }, + + { // Quality B, correction for frame width + "make_model": "Sony ILCE-7S", + "dcraw_matrix": [ 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 ], // DNG D65 + "raw_crop": [ 0, 0, 4254, 2848 ], + "ranges": { "black": 512, "white": 16300 } + }, + { // Quality A, + "make_model": [ "Sony DSC-RX100M3", "Sony DSC-RX100M4" ], + "dcraw_matrix": [ 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 ], // DNG_v9.1.1 D65 + "ranges": { "black": 800, "white": 16300 } + }, + { // Quality B, + "make_model": "Sony DSC-RX10M2", + "dcraw_matrix": [ 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 ], // DNG_v9.1.1 D65 + "ranges": { "black": 800, "white": 16300 } + }, + + /* Phase One: color matrices borrowed from Adobe DNG Converter, black/white levels tested on actual raw files. + Note: the dcraw decoder makes black level subtraction and various corrections to the raw values based on + metadata embedded in the IIQ format, so what we see here is the result after that, ie black level is 0, + and white level is typically at or close to 65535. However sensors vary a bit and can be noisy around clip + so we cut away 0.05 stop from top down to 63300 to be a bit conservative. */ + { // quality A + "make_model": [ "Phase One P40+", "Phase One IQ140", "Leaf Credo 40", "Phase One P65+", "Phase One IQ160", "Leaf Credo 60", "Phase One IQ260" ], + "dcraw_matrix": [ 8035,435,-962,-6001,13872,2320,-1159,3065,5434 ], + "ranges": { "black": 0, "white": 63300 } + }, + { // quality A + "make_model": [ "Phase One IQ180", "Leaf Credo 80", "Phase One IQ280" ], + "dcraw_matrix": [ 6294,686,-712,-5435,13417,2211,-1006,2435,5042 ], + "ranges": { "black": 0, "white": 63300 } + }, + { // quality A + "make_model": [ "Phase One P20", "Phase One P20+", "Phase One P25", "Phase One P25+" ], + "dcraw_matrix": [ 2905,732,-237,-8135,16626,1476,-3038,4253,7517 ], + "ranges": { "black": 0, "white": 63300 } + }, + { // quality A + "make_model": [ "Phase One P21", "Phase One P21+" ], + "dcraw_matrix": [ 6516,-2050,-507,-8217,16703,1479,-3492,4741,8489 ], + "ranges": { "black": 0, "white": 63300 } + }, + { // quality A + "make_model": [ "Phase One P30", "Phase One P30+"], + "dcraw_matrix": [ 4516,-244,-36,-7020,14976,2174,-3206,4670,7087 ], + "ranges": { "black": 0, "white": 63300 } + }, + { // quality A + "make_model": [ "Phase One P45", "Phase One P45+" ], + "dcraw_matrix": [ 5053,-24,-117,-5685,14077,1703,-2619,4491,5850 ], + "ranges": { "black": 0, "white": 63300 } + }, + { // quality X, matrix taken from H5D-50c which has the same sensor, probably with the same CFA. Color looks good to the eye with files tested. + "make_model": [ "Phase One IQ250", "Leaf Credo 50" ], + "dcraw_matrix": [ 4932, -835, 141, -4878, 11868, 3437, -1138, 1961, 7067 ], + "ranges": { "black": 0, "white": 64400 } // CMOS sensor, we dare to set white level a bit higher than for the more varying Phase One CCDs + }, + + { // Quality A for tested CFV, the other models have the same sensor (16 megapixel square sensor) + "make_model": [ "Hasselblad V96C", "Hasselblad CFV", "Hasselblad CFV-II" ], + "dcraw_matrix": [ 8519, -3260, -280, -5081, 13459, 1738, -1449, 2960, 7809 ] // borrowed from Adobe's DNG converter + }, + { // Quality A for tested CF-22, the other models have the same sensor + "make_model": [ "Hasselblad CF-22", "Hasselblad CF-22MS", "Hasselblad CFH-22", "Hasselblad H3D-22", "Hasselblad H3DII-22" ], + "dcraw_matrix": [ 8519, -3260, -280, -5081, 13459, 1738, -1449, 2960, 7809 ] // borrowed from Adobe's DNG converter + }, + { // Quality A for tested H3D-31, the other models have the same sensor + "make_model": [ "Hasselblad H3D-31", "Hasselblad H3DII-31", "Hasselblad H4D-31" ], + "dcraw_matrix": [ 5458, -1448, 145, -4479, 12338, 2401, -1659, 3086, 6710 ] // borrowed from Adobe's DNG converter + }, + { // Quality A for tested CFV-39, the other models have the same sensor. Small filter differences may exist so some might do better with a slightly different profile + "make_model": [ "Hasselblad CF-39", "Hasselblad CF-39MS", "Hasselblad CFH-39", "Hasselblad CFV-39", "Hasselblad H3D-39", "Hasselblad H3DII-39", "Hasselblad H3DII-39MS" ], + "dcraw_matrix": [ 3857, 452, -46, -6008, 14477, 1596, -2627, 4481, 5718 ] // borrowed from Adobe's DNG converter + }, + { // Quality A for tested CFV-50, the other models have the same sensor + "make_model": [ "Hasselblad CFV-50", "Hasselblad H3DII-50", "Hasselblad H3DII-50MS", "Hasselblad H4D-50", "Hasselblad H4D-50MS", "Hasselblad H4D-200MS", "Hasselblad H5D-50", "Hasselblad H5D-50MS", "Hasselblad H5D-200MS" ], + "dcraw_matrix": [ 5656, -659, -346, -3923, 12306, 1791, -1602, 3509, 5442 ] // borrowed from Adobe's DNG converter + }, + { // Quality A + "make_model": [ "Hasselblad H4D-40", "Hasselblad H5D-40" ], + "dcraw_matrix": [ 6159, -1402, -177, -5439, 12762, 3007, -955, 2200, 7104 ] // borrowed from Adobe's DNG converter + }, + { // Quality A for tested H4D-60, the other models have the same sensor + "make_model": [ "Hasselblad H4D-60", "Hasselblad H5D-60" ], + "dcraw_matrix": [ 9662, -684, -279, -4903, 12293, 2950, -344, 1669, 6024 ] // borrowed from Adobe's DNG converter + }, + { // Quality A + "make_model": [ "Hasselblad H5D-50c", "Hasselblad CFV-50c" ], + "dcraw_matrix": [ 4932, -835, 141, -4878, 11868, 3437, -1138, 1961, 7067 ] + }, + + // dummy test entry to test the parser and show the format with all entries active + { + "make_model": "DummyMake DummyModel", + "dcraw_matrix": [ 7530,-1942,-255,-4318,11390,3362,-926,1694,7649 ], + "raw_crop": [ 10, 20, 4000, 3000 ], + "masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ], + "ranges": { + "aperture_scaling": [ + { "aperture": 1.2, "scale_factor": 1.1 }, + { "aperture": 1.4, "scale_factor": 1.08 } + ], + "black": [ + { "iso": 100 , "levels": [ 10, 20, 10, 20 ] }, + { "iso": [100, 200] , "levels": [ 30, 40, 30 ] }, + { "iso": 3200, "levels": [ 50, 60, 50, 60 ] } + ], + "white": [ + { "iso": 100 , "levels": [ 10000, 11000, 10000, 11000 ] }, + { "iso": 3200, "levels": [ 11000, 11000, 10000, 11000 ] } + ], + "white_max": 16383 + } + } +]} diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index 119bbecc5..c43bc8138 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -1,394 +1,394 @@ -#include "clutstore.h" -#include "rt_math.h" -#include "stdimagesource.h" -#include "safegtk.h" +#include "clutstore.h" +#include "rt_math.h" +#include "stdimagesource.h" +#include "safegtk.h" #include "../rtgui/options.h" - -rtengine::CLUTStore clutStore; - -using namespace rtengine; - -const float MAXVAL8 = 255.; - -CLUTStore::CLUTStore() -{ -} - -CLUT* CLUTStore::getClut( const Glib::ustring& filename ) -{ - CLUT *result = 0; - m_mutex.lock(); - Cluts::iterator cluts_it = m_cluts.find(filename); - if (cluts_it == m_cluts.end()) { - if (m_cluts.size() >= options.clutCacheSize) { - // Evict a "random" entry from cache - Cluts::iterator victim_it = m_cluts.begin(); - if (--victim_it->second.first == -1) { - delete victim_it->second.second; - m_cluts.erase(victim_it); - } - } - cluts_it = m_cluts.insert(std::make_pair(filename, std::make_pair(0, new HaldCLUT))).first; - cluts_it->second.second->load( filename ); - } - if (cluts_it->second.second->isValid()) { - result = cluts_it->second.second; - ++cluts_it->second.first; - } else { - delete cluts_it->second.second; - m_cluts.erase(cluts_it); - } - m_mutex.unlock(); - - return result; -} - -void CLUTStore::releaseClut( const CLUT* clut ) -{ - m_mutex.lock(); - for (Cluts::iterator cluts_it = m_cluts.begin(); cluts_it != m_cluts.end(); ++cluts_it) { - if (cluts_it->second.second == clut) { - if (--cluts_it->second.first == -1) { - delete cluts_it->second.second; - m_cluts.erase(cluts_it); - } - break; - } - } - m_mutex.unlock(); -} - -void CLUTStore::clearCache() -{ - m_mutex.lock(); - for (Cluts::iterator cluts_it = m_cluts.begin(); cluts_it != m_cluts.end();) { - if (--cluts_it->second.first == -1) { - delete cluts_it->second.second; - Cluts::iterator tmp = cluts_it; - ++cluts_it; - m_cluts.erase(tmp); - } else { - ++cluts_it; - } - } - m_mutex.unlock(); -} - -void rtengine::splitClutFilename( Glib::ustring filename, Glib::ustring &name, Glib::ustring &extension, Glib::ustring &profileName ) -{ - filename = Glib::path_get_basename( filename ); - name = filename; - //remove dirs - size_t lastSlashPos = filename.find_last_of( "/" ); - if ( lastSlashPos == Glib::ustring::npos ) { - lastSlashPos = filename.find_last_of( "\\" ); - } - - size_t lastDotPos = filename.find_last_of( '.' ); - if ( lastDotPos != Glib::ustring::npos ) { - name = filename.substr( 0, lastDotPos ); - extension = filename.substr( lastDotPos + 1, Glib::ustring::npos ); - } - profileName = "sRGB"; // sRGB by default - static std::vector workingProfiles = rtengine::getWorkingProfiles(); - for ( std::vector::iterator it = workingProfiles.begin(); it != workingProfiles.end(); ++it ) { - Glib::ustring ¤tProfile = *it; - if ( std::search( name.rbegin(), name.rend(), currentProfile.rbegin(), currentProfile.rend() ) == name.rbegin() ) { - profileName = currentProfile; - name = name.substr( 0, name.size() - currentProfile.size() ); - break; - } - } -} - -//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -HaldCLUT::HaldCLUT() -: m_clutImage( 0 ), - m_level (0), - m_profile( "sRGB" ) -{ -} - -HaldCLUT::~HaldCLUT() -{ - if ( m_clutImage ) { - m_clutImage->free(); - m_clutImage = 0; - } -} - -void HaldCLUT::load( Glib::ustring filename ) -{ - m_clutImage = loadFile( filename, "", m_level ); - Glib::ustring name, ext; - splitClutFilename( filename, name, ext, m_profile ); - if ( m_clutImage ) { - m_filename = filename; - } -} - -Glib::ustring HaldCLUT::profile() const -{ - return m_profile; -} - -Imagefloat* HaldCLUT::loadFile( Glib::ustring filename, Glib::ustring workingColorSpace, int &outLevel ) -{ - Imagefloat *result = 0; - StdImageSource imgSrc; - if ( !safe_file_test( filename, Glib::FILE_TEST_EXISTS ) || imgSrc.load(filename) ) { - return result; - } - - int fw, fh; - imgSrc.getFullSize (fw, fh, TR_NONE); - - bool valid = false; - //test on Hald format, copypasted from http://www.quelsolaar.com/technology/clut.html - if ( fw == fh ) { - outLevel = 1; - for(; outLevel * outLevel * outLevel < fw; outLevel++); - if( !( outLevel * outLevel * outLevel > fw ) ) { - valid = true; - } - } - - if ( valid ) { - ColorTemp currWB = imgSrc.getWB(); - Imagefloat* baseImg = new Imagefloat (fw, fh); - PreviewProps pp (0, 0, fw, fh, 1); - - procparams::ColorManagementParams icm; - icm.working = workingColorSpace; - - imgSrc.getImage (currWB, TR_NONE, baseImg, pp, procparams::ToneCurveParams(), icm, procparams::RAWParams()); - if ( !workingColorSpace.empty() ) { - imgSrc.convertColorSpace(baseImg, icm, currWB); - } - result = baseImg; - } - return result; -} - -void HaldCLUT::loadClut( Imagefloat *img, RawClut &outClut ) -{ - img->normalizeFloatTo1(); - int y_size = img->getH(); - int x_size = img->getW(); - outClut.resize( x_size * y_size * 3 ); - int clutIdx = 0; - //int level = m_level * m_level; (unused) - for(int y = 0; y < y_size; y++) { - for(int x = 0; x < x_size; x++) { - outClut[ clutIdx * 3 ] = img->r( y, x ) * MAXVAL8; - outClut[ clutIdx * 3 + 1 ] = img->g( y, x ) * MAXVAL8; - outClut[ clutIdx * 3 + 2 ] = img->b( y, x ) * MAXVAL8; - - ++clutIdx; - } - } -} - -Imagefloat* HaldCLUT::generateIdentImage( int level ) -{ - int imageWidth = level * level * level; - Imagefloat *resultImg = new Imagefloat( imageWidth, imageWidth ); - - int cubeSideSize = level * level; - float step = MAXVALF / (cubeSideSize - 1); - int pos = 0; - for( int b = 0; b < cubeSideSize; ++b ) { - for ( int g = 0; g < cubeSideSize; ++g ) { - for ( int r = 0; r < cubeSideSize; ++r ) { - int x = pos / imageWidth; - int y = pos % imageWidth; - resultImg->r( x, y ) = step * r; - resultImg->g( x, y ) = step * g; - resultImg->b( x, y ) = step * b; - ++pos; - } - } - } - return resultImg; -} - - -bool HaldCLUT::isValid() const -{ - return m_clutImage != 0; -} - -void HaldCLUT::getRGB( float rr, float gg, float bb, float &outR, float &outG, float &outB ) const -{ - rr /= MAXVALF; - gg /= MAXVALF; - bb /= MAXVALF; - correct( *m_clutImage, m_level, rr, gg, bb, outR, outG, outB ); -} - -inline float valF( unsigned char val ) -{ - return float( val ) / MAXVAL8; -} - -// copypasted from http://www.quelsolaar.com/technology/clut.html -void HaldCLUT::correct( const HaldCLUT::RawClut& clut, int level, float rr, float gg, float bb, float &outR, float &outG, float &outB ) -{ - int color, red, green, blue, i, j; - float tmp[6], r, g, b; - level = level * level; - - red = rr * (float)(level - 1); - if(red > level - 2) - red = (float)level - 2; - if(red < 0) - red = 0; - - green = gg * (float)(level - 1); - if(green > level - 2) - green = (float)level - 2; - if(green < 0) - green = 0; - - blue = bb * (float)(level - 1); - if(blue > level - 2) - blue = (float)level - 2; - if(blue < 0) - blue = 0; - - r = rr * (float)(level - 1) - red; - g = gg * (float)(level - 1) - green; - b = bb * (float)(level - 1) - blue; - - color = red + green * level + blue * level * level; - - i = color * 3; - j = (color + 1) * 3; - - tmp[0] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; - tmp[1] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; - tmp[2] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r; - - i = (color + level) * 3; - j = (color + level + 1) * 3; - - tmp[3] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; - tmp[4] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; - tmp[5] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r; - - outR = tmp[0] * (1 - g) + tmp[3] * g; - outG = tmp[1] * (1 - g) + tmp[4] * g; - outB = tmp[2] * (1 - g) + tmp[5] * g; - - i = (color + level * level) * 3; - j = (color + level * level + 1) * 3; - - tmp[0] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; - tmp[1] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; - tmp[2] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r; - - i = (color + level + level * level) * 3; - j = (color + level + level * level + 1) * 3; - - tmp[3] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; - tmp[4] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; - tmp[5] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r; - - tmp[0] = tmp[0] * (1 - g) + tmp[3] * g; - tmp[1] = tmp[1] * (1 - g) + tmp[4] * g; - tmp[2] = tmp[2] * (1 - g) + tmp[5] * g; - - outR = outR * (1 - b) + tmp[0] * b; - outG = outG * (1 - b) + tmp[1] * b; - outB = outB * (1 - b) + tmp[2] * b; -} - -inline void pos2xy( int pos, int imageSideSize, int &outX, int &outY ) -{ - outX = pos / imageSideSize; - outY = pos % imageSideSize; -} - -void HaldCLUT::correct( Imagefloat &clutImage, int level, float rr, float gg, float bb, float &outR, float &outG, float &outB ) -{ - int color, red, green, blue, i, j; - float tmp[6], r, g, b; - level = level * level; - int imageSideSize = clutImage.getW(); - - red = rr * (float)(level - 1); - if(red > level - 2) - red = (float)level - 2; - if(red < 0) - red = 0; - - green = gg * (float)(level - 1); - if(green > level - 2) - green = (float)level - 2; - if(green < 0) - green = 0; - - blue = bb * (float)(level - 1); - if(blue > level - 2) - blue = (float)level - 2; - if(blue < 0) - blue = 0; - - r = rr * (float)(level - 1) - red; - g = gg * (float)(level - 1) - green; - b = bb * (float)(level - 1) - blue; - - color = red + green * level + blue * level * level; - - - i = color; - j = color + 1; - int xi, yi, xj, yj; - pos2xy( i, imageSideSize, xi, yi ); - pos2xy( j, imageSideSize, xj, yj ); - - tmp[0] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r; - tmp[1] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r; - tmp[2] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r; - - i = color + level; - j = color + level + 1; - pos2xy( i, imageSideSize, xi, yi ); - pos2xy( j, imageSideSize, xj, yj ); - - tmp[3] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r; - tmp[4] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r; - tmp[5] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r; - - outR = tmp[0] * (1 - g) + tmp[3] * g; - outG = tmp[1] * (1 - g) + tmp[4] * g; - outB = tmp[2] * (1 - g) + tmp[5] * g; - - i = color + level * level; - j = color + level * level + 1; - pos2xy( i, imageSideSize, xi, yi ); - pos2xy( j, imageSideSize, xj, yj ); - - tmp[0] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r; - tmp[1] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r; - tmp[2] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r; - - i = color + level + level * level; - j = color + level + level * level + 1; - pos2xy( i, imageSideSize, xi, yi ); - pos2xy( j, imageSideSize, xj, yj ); - - tmp[3] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r; - tmp[4] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r; - tmp[5] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r; - - tmp[0] = tmp[0] * (1 - g) + tmp[3] * g; - tmp[1] = tmp[1] * (1 - g) + tmp[4] * g; - tmp[2] = tmp[2] * (1 - g) + tmp[5] * g; - - outR = outR * (1 - b) + tmp[0] * b; - outG = outG * (1 - b) + tmp[1] * b; - outB = outB * (1 - b) + tmp[2] * b; -} +rtengine::CLUTStore clutStore; + +using namespace rtengine; + +const float MAXVAL8 = 255.; + +CLUTStore::CLUTStore() +{ +} + +CLUT* CLUTStore::getClut( const Glib::ustring& filename ) +{ + CLUT *result = 0; + m_mutex.lock(); + Cluts::iterator cluts_it = m_cluts.find(filename); + if (cluts_it == m_cluts.end()) { + if (m_cluts.size() >= options.clutCacheSize) { + // Evict a "random" entry from cache + Cluts::iterator victim_it = m_cluts.begin(); + if (--victim_it->second.first == -1) { + delete victim_it->second.second; + m_cluts.erase(victim_it); + } + } + cluts_it = m_cluts.insert(std::make_pair(filename, std::make_pair(0, new HaldCLUT))).first; + cluts_it->second.second->load( filename ); + } + if (cluts_it->second.second->isValid()) { + result = cluts_it->second.second; + ++cluts_it->second.first; + } else { + delete cluts_it->second.second; + m_cluts.erase(cluts_it); + } + m_mutex.unlock(); + + return result; +} + +void CLUTStore::releaseClut( const CLUT* clut ) +{ + m_mutex.lock(); + for (Cluts::iterator cluts_it = m_cluts.begin(); cluts_it != m_cluts.end(); ++cluts_it) { + if (cluts_it->second.second == clut) { + if (--cluts_it->second.first == -1) { + delete cluts_it->second.second; + m_cluts.erase(cluts_it); + } + break; + } + } + m_mutex.unlock(); +} + +void CLUTStore::clearCache() +{ + m_mutex.lock(); + for (Cluts::iterator cluts_it = m_cluts.begin(); cluts_it != m_cluts.end();) { + if (--cluts_it->second.first == -1) { + delete cluts_it->second.second; + Cluts::iterator tmp = cluts_it; + ++cluts_it; + m_cluts.erase(tmp); + } else { + ++cluts_it; + } + } + m_mutex.unlock(); +} + +void rtengine::splitClutFilename( Glib::ustring filename, Glib::ustring &name, Glib::ustring &extension, Glib::ustring &profileName ) +{ + filename = Glib::path_get_basename( filename ); + name = filename; + //remove dirs + size_t lastSlashPos = filename.find_last_of( "/" ); + if ( lastSlashPos == Glib::ustring::npos ) { + lastSlashPos = filename.find_last_of( "\\" ); + } + + size_t lastDotPos = filename.find_last_of( '.' ); + if ( lastDotPos != Glib::ustring::npos ) { + name = filename.substr( 0, lastDotPos ); + extension = filename.substr( lastDotPos + 1, Glib::ustring::npos ); + } + + profileName = "sRGB"; // sRGB by default + static std::vector workingProfiles = rtengine::getWorkingProfiles(); + for ( std::vector::iterator it = workingProfiles.begin(); it != workingProfiles.end(); ++it ) { + Glib::ustring ¤tProfile = *it; + if ( std::search( name.rbegin(), name.rend(), currentProfile.rbegin(), currentProfile.rend() ) == name.rbegin() ) { + profileName = currentProfile; + name = name.substr( 0, name.size() - currentProfile.size() ); + break; + } + } +} + +//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +HaldCLUT::HaldCLUT() +: m_clutImage( 0 ), + m_level (0), + m_profile( "sRGB" ) +{ +} + +HaldCLUT::~HaldCLUT() +{ + if ( m_clutImage ) { + m_clutImage->free(); + m_clutImage = 0; + } +} + +void HaldCLUT::load( Glib::ustring filename ) +{ + m_clutImage = loadFile( filename, "", m_level ); + Glib::ustring name, ext; + splitClutFilename( filename, name, ext, m_profile ); + if ( m_clutImage ) { + m_filename = filename; + } +} + +Glib::ustring HaldCLUT::profile() const +{ + return m_profile; +} + +Imagefloat* HaldCLUT::loadFile( Glib::ustring filename, Glib::ustring workingColorSpace, int &outLevel ) +{ + Imagefloat *result = 0; + StdImageSource imgSrc; + if ( !safe_file_test( filename, Glib::FILE_TEST_EXISTS ) || imgSrc.load(filename) ) { + return result; + } + + int fw, fh; + imgSrc.getFullSize (fw, fh, TR_NONE); + + bool valid = false; + //test on Hald format, copypasted from http://www.quelsolaar.com/technology/clut.html + if ( fw == fh ) { + outLevel = 1; + for(; outLevel * outLevel * outLevel < fw; outLevel++); + if( !( outLevel * outLevel * outLevel > fw ) ) { + valid = true; + } + } + + if ( valid ) { + ColorTemp currWB = imgSrc.getWB(); + Imagefloat* baseImg = new Imagefloat (fw, fh); + PreviewProps pp (0, 0, fw, fh, 1); + + procparams::ColorManagementParams icm; + icm.working = workingColorSpace; + + imgSrc.getImage (currWB, TR_NONE, baseImg, pp, procparams::ToneCurveParams(), icm, procparams::RAWParams()); + if ( !workingColorSpace.empty() ) { + imgSrc.convertColorSpace(baseImg, icm, currWB); + } + result = baseImg; + } + return result; +} + +void HaldCLUT::loadClut( Imagefloat *img, RawClut &outClut ) +{ + img->normalizeFloatTo1(); + int y_size = img->getH(); + int x_size = img->getW(); + outClut.resize( x_size * y_size * 3 ); + int clutIdx = 0; + //int level = m_level * m_level; (unused) + for(int y = 0; y < y_size; y++) { + for(int x = 0; x < x_size; x++) { + outClut[ clutIdx * 3 ] = img->r( y, x ) * MAXVAL8; + outClut[ clutIdx * 3 + 1 ] = img->g( y, x ) * MAXVAL8; + outClut[ clutIdx * 3 + 2 ] = img->b( y, x ) * MAXVAL8; + + ++clutIdx; + } + } +} + +Imagefloat* HaldCLUT::generateIdentImage( int level ) +{ + int imageWidth = level * level * level; + Imagefloat *resultImg = new Imagefloat( imageWidth, imageWidth ); + + int cubeSideSize = level * level; + float step = MAXVALF / (cubeSideSize - 1); + int pos = 0; + for( int b = 0; b < cubeSideSize; ++b ) { + for ( int g = 0; g < cubeSideSize; ++g ) { + for ( int r = 0; r < cubeSideSize; ++r ) { + int x = pos / imageWidth; + int y = pos % imageWidth; + resultImg->r( x, y ) = step * r; + resultImg->g( x, y ) = step * g; + resultImg->b( x, y ) = step * b; + ++pos; + } + } + } + return resultImg; +} + + +bool HaldCLUT::isValid() const +{ + return m_clutImage != 0; +} + +void HaldCLUT::getRGB( float rr, float gg, float bb, float &outR, float &outG, float &outB ) const +{ + rr /= MAXVALF; + gg /= MAXVALF; + bb /= MAXVALF; + correct( *m_clutImage, m_level, rr, gg, bb, outR, outG, outB ); +} + +inline float valF( unsigned char val ) +{ + return float( val ) / MAXVAL8; +} + +// copypasted from http://www.quelsolaar.com/technology/clut.html +void HaldCLUT::correct( const HaldCLUT::RawClut& clut, int level, float rr, float gg, float bb, float &outR, float &outG, float &outB ) +{ + int color, red, green, blue, i, j; + float tmp[6], r, g, b; + level = level * level; + + red = rr * (float)(level - 1); + if(red > level - 2) + red = (float)level - 2; + if(red < 0) + red = 0; + + green = gg * (float)(level - 1); + if(green > level - 2) + green = (float)level - 2; + if(green < 0) + green = 0; + + blue = bb * (float)(level - 1); + if(blue > level - 2) + blue = (float)level - 2; + if(blue < 0) + blue = 0; + + r = rr * (float)(level - 1) - red; + g = gg * (float)(level - 1) - green; + b = bb * (float)(level - 1) - blue; + + color = red + green * level + blue * level * level; + + i = color * 3; + j = (color + 1) * 3; + + tmp[0] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; + tmp[1] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; + tmp[2] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r; + + i = (color + level) * 3; + j = (color + level + 1) * 3; + + tmp[3] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; + tmp[4] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; + tmp[5] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r; + + outR = tmp[0] * (1 - g) + tmp[3] * g; + outG = tmp[1] * (1 - g) + tmp[4] * g; + outB = tmp[2] * (1 - g) + tmp[5] * g; + + i = (color + level * level) * 3; + j = (color + level * level + 1) * 3; + + tmp[0] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; + tmp[1] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; + tmp[2] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r; + + i = (color + level + level * level) * 3; + j = (color + level + level * level + 1) * 3; + + tmp[3] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; + tmp[4] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r; + tmp[5] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r; + + tmp[0] = tmp[0] * (1 - g) + tmp[3] * g; + tmp[1] = tmp[1] * (1 - g) + tmp[4] * g; + tmp[2] = tmp[2] * (1 - g) + tmp[5] * g; + + outR = outR * (1 - b) + tmp[0] * b; + outG = outG * (1 - b) + tmp[1] * b; + outB = outB * (1 - b) + tmp[2] * b; +} + +inline void pos2xy( int pos, int imageSideSize, int &outX, int &outY ) +{ + outX = pos / imageSideSize; + outY = pos % imageSideSize; +} + +void HaldCLUT::correct( Imagefloat &clutImage, int level, float rr, float gg, float bb, float &outR, float &outG, float &outB ) +{ + int color, red, green, blue, i, j; + float tmp[6], r, g, b; + level = level * level; + int imageSideSize = clutImage.getW(); + + red = rr * (float)(level - 1); + if(red > level - 2) + red = (float)level - 2; + if(red < 0) + red = 0; + + green = gg * (float)(level - 1); + if(green > level - 2) + green = (float)level - 2; + if(green < 0) + green = 0; + + blue = bb * (float)(level - 1); + if(blue > level - 2) + blue = (float)level - 2; + if(blue < 0) + blue = 0; + + r = rr * (float)(level - 1) - red; + g = gg * (float)(level - 1) - green; + b = bb * (float)(level - 1) - blue; + + color = red + green * level + blue * level * level; + + + i = color; + j = color + 1; + int xi, yi, xj, yj; + pos2xy( i, imageSideSize, xi, yi ); + pos2xy( j, imageSideSize, xj, yj ); + + tmp[0] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r; + tmp[1] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r; + tmp[2] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r; + + i = color + level; + j = color + level + 1; + pos2xy( i, imageSideSize, xi, yi ); + pos2xy( j, imageSideSize, xj, yj ); + + tmp[3] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r; + tmp[4] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r; + tmp[5] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r; + + outR = tmp[0] * (1 - g) + tmp[3] * g; + outG = tmp[1] * (1 - g) + tmp[4] * g; + outB = tmp[2] * (1 - g) + tmp[5] * g; + + i = color + level * level; + j = color + level * level + 1; + pos2xy( i, imageSideSize, xi, yi ); + pos2xy( j, imageSideSize, xj, yj ); + + tmp[0] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r; + tmp[1] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r; + tmp[2] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r; + + i = color + level + level * level; + j = color + level + level * level + 1; + pos2xy( i, imageSideSize, xi, yi ); + pos2xy( j, imageSideSize, xj, yj ); + + tmp[3] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r; + tmp[4] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r; + tmp[5] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r; + + tmp[0] = tmp[0] * (1 - g) + tmp[3] * g; + tmp[1] = tmp[1] * (1 - g) + tmp[4] * g; + tmp[2] = tmp[2] * (1 - g) + tmp[5] * g; + + outR = outR * (1 - b) + tmp[0] * b; + outG = outG * (1 - b) + tmp[1] * b; + outB = outB * (1 - b) + tmp[2] * b; +} diff --git a/rtengine/clutstore.h b/rtengine/clutstore.h index 2ef9de490..679c8531c 100644 --- a/rtengine/clutstore.h +++ b/rtengine/clutstore.h @@ -1,93 +1,93 @@ -#ifndef CLUT_STORE_INCLUDED -#define CLUT_STORE_INCLUDED - -#include -#include "../rtgui/threadutils.h" -#include "imagefloat.h" -#include -#include - -namespace rtengine { - -// simple CLUT interface -class CLUT -{ -public: - virtual void getRGB( float r, float g, float b, float &outR, float &outG, float &outB ) const = 0; - virtual Glib::ustring profile() const = 0; -protected: - virtual ~CLUT() {}; -}; - -class HaldCLUT : public CLUT -{ -public: - HaldCLUT(); - ~HaldCLUT(); - void load( Glib::ustring filename ); - bool isValid() const; - - void getRGB( float r, float g, float b, float &outR, float &outG, float &outB ) const; - Glib::ustring profile() const; - - typedef std::vector RawClut; // using 8 bit for reduce memory usage - static void correct( const RawClut&, int level, float r, float g, float b, float &outR, float &outG, float &outB ); - static void correct( Imagefloat &clutImage, int level, float rr, float gg, float bb, float &outR, float &outG, float &outB ); - static Imagefloat* generateIdentImage( int level ); - static Imagefloat* loadFile( Glib::ustring filename, Glib::ustring workingColorSpace, int &outLevel ); - -private: - - void loadClut( Imagefloat *img, RawClut &outClut ); - - Imagefloat *m_clutImage; - int m_level; - Glib::ustring m_filename; - Glib::ustring m_profile; -}; - -// CLUT cache -class CLUTStore -{ -public: - CLUTStore(); - - CLUT* getClut( const Glib::ustring& filename ); - void releaseClut( const CLUT* clut ); - - void clearCache(); - -private: - typedef std::map > Cluts; - - Cluts m_cluts; - MyMutex m_mutex; -}; - -void splitClutFilename( Glib::ustring filename, Glib::ustring &name, Glib::ustring &extension, Glib::ustring &profileName ); - -}; //namespace rtengine - -extern rtengine::CLUTStore clutStore; - -namespace rtengine { - -//support class for automate call of clutStore.releaseClut() -class ClutPtr -{ -public: - ClutPtr() : m_point( 0 ) {} - explicit ClutPtr(CLUT *p) : m_point( p ) {} - ~ClutPtr() { clutStore.releaseClut( m_point ); } - const CLUT* operator-> () const { return m_point; } - operator bool() const { return m_point != 0; } - void set( CLUT *p ) { m_point = p; } - -private: - ClutPtr& operator=(ClutPtr const& cp ); - CLUT *m_point; -}; - -}; //namespace rtengine - -#endif +#ifndef CLUT_STORE_INCLUDED +#define CLUT_STORE_INCLUDED + +#include +#include "../rtgui/threadutils.h" +#include "imagefloat.h" +#include +#include + +namespace rtengine { + +// simple CLUT interface +class CLUT +{ +public: + virtual void getRGB( float r, float g, float b, float &outR, float &outG, float &outB ) const = 0; + virtual Glib::ustring profile() const = 0; +protected: + virtual ~CLUT() {}; +}; + +class HaldCLUT : public CLUT +{ +public: + HaldCLUT(); + ~HaldCLUT(); + void load( Glib::ustring filename ); + bool isValid() const; + + void getRGB( float r, float g, float b, float &outR, float &outG, float &outB ) const; + Glib::ustring profile() const; + + typedef std::vector RawClut; // using 8 bit for reduce memory usage + static void correct( const RawClut&, int level, float r, float g, float b, float &outR, float &outG, float &outB ); + static void correct( Imagefloat &clutImage, int level, float rr, float gg, float bb, float &outR, float &outG, float &outB ); + static Imagefloat* generateIdentImage( int level ); + static Imagefloat* loadFile( Glib::ustring filename, Glib::ustring workingColorSpace, int &outLevel ); + +private: + + void loadClut( Imagefloat *img, RawClut &outClut ); + + Imagefloat *m_clutImage; + int m_level; + Glib::ustring m_filename; + Glib::ustring m_profile; +}; + +// CLUT cache +class CLUTStore +{ +public: + CLUTStore(); + + CLUT* getClut( const Glib::ustring& filename ); + void releaseClut( const CLUT* clut ); + + void clearCache(); + +private: + typedef std::map > Cluts; + + Cluts m_cluts; + MyMutex m_mutex; +}; + +void splitClutFilename( Glib::ustring filename, Glib::ustring &name, Glib::ustring &extension, Glib::ustring &profileName ); + +}; //namespace rtengine + +extern rtengine::CLUTStore clutStore; + +namespace rtengine { + +//support class for automate call of clutStore.releaseClut() +class ClutPtr +{ +public: + ClutPtr() : m_point( 0 ) {} + explicit ClutPtr(CLUT *p) : m_point( p ) {} + ~ClutPtr() { clutStore.releaseClut( m_point ); } + const CLUT* operator-> () const { return m_point; } + operator bool() const { return m_point != 0; } + void set( CLUT *p ) { m_point = p; } + +private: + ClutPtr& operator=(ClutPtr const& cp ); + CLUT *m_point; +}; + +}; //namespace rtengine + +#endif diff --git a/rtengine/color.cc b/rtengine/color.cc index 099612923..476c369cb 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -1,3584 +1,3584 @@ -/* -* This file is part of RawTherapee. -* -* Copyright (c) 2004-2010 Gabor Horvath -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -*/ - -#include "rtengine.h" -#include "color.h" -#include "iccmatrices.h" -#include "mytime.h" -#include "sleef.c" -#include "opthelper.h" - -using namespace std; - -namespace rtengine { - - extern const Settings* settings; - - cmsToneCurve* Color::linearGammaTRC; - LUTf Color::cachef; - LUTf Color::gamma2curve; - - LUTf Color::gammatab; - LUTf Color::igammatab_srgb; - LUTf Color::gammatab_srgb; - // LUTf Color::igammatab_709; -// LUTf Color::gammatab_709; - LUTf Color::igammatab_55; - LUTf Color::gammatab_55; - LUTf Color::igammatab_4; - LUTf Color::gammatab_4; - - LUTf Color::igammatab_26_11; - LUTf Color::gammatab_26_11; - LUTf Color::igammatab_24_17; - LUTf Color::gammatab_24_17a; - LUTf Color::gammatab_13_2; - - // Wikipedia sRGB: Unlike most other RGB color spaces, the sRGB gamma cannot be expressed as a single numerical value. - // The overall gamma is approximately 2.2, consisting of a linear (gamma 1.0) section near black, and a non-linear section elsewhere involving a 2.4 exponent - // and a gamma (slope of log output versus log input) changing from 1.0 through about 2.3. - const double Color::sRGBGamma = 2.2; - const double Color::sRGBGammaCurve = 2.4; - - const double Color::eps_max=580.40756; //(MAXVALF* 216.0f/24389.0); - const double Color::eps=216.0f/24389.0;//0.008856 - const double Color::kappa=24389.0/27.0;//903.29630; - - const float Color::D50x=0.9642f; //0.96422; - const float Color::D50z=0.8249f; //0.82521; - const double Color::u0=4.0*D50x/(D50x+15+3*D50z); - const double Color::v0=9.0/(D50x+15+3*D50z); - const double Color::epskap=8.0; - /* - * Munsell Lch correction - * Copyright (c) 2011 Jacques Desmis - */ - // Munsell Lch LUTf : 195 LUT - // about 70% data are corrected with significative corrections - // almost all data are taken for BG, YR, G excepted a few extreme values with a slight correction - // No LUTf for BG and Y : low corrections - // Only between 5B and 5PB for L > 40 : under very low corrections for L < 40 - - //give hue in function of L and C : Munsell correction - LUTf Color::_4P10, Color::_4P20, Color::_4P30, Color::_4P40, Color::_4P50, Color::_4P60; - LUTf Color::_1P10, Color::_1P20, Color::_1P30, Color::_1P40, Color::_1P50, Color::_1P60; - LUTf Color::_10PB10, Color::_10PB20, Color::_10PB30, Color::_10PB40, Color::_10PB50, Color::_10PB60; - LUTf Color::_9PB10, Color::_9PB20, Color::_9PB30, Color::_9PB40, Color::_9PB50, Color::_9PB60, Color::_9PB70, Color::_9PB80; - LUTf Color::_75PB10, Color::_75PB20, Color::_75PB30, Color::_75PB40, Color::_75PB50, Color::_75PB60, Color::_75PB70, Color::_75PB80; - LUTf Color::_6PB10, Color::_6PB20, Color::_6PB30, Color::_6PB40, Color::_6PB50, Color::_6PB60, Color::_6PB70, Color::_6PB80; - LUTf Color::_45PB10, Color::_45PB20, Color::_45PB30, Color::_45PB40, Color::_45PB50, Color::_45PB60, Color::_45PB70, Color::_45PB80; - LUTf Color::_3PB10, Color::_3PB20, Color::_3PB30, Color::_3PB40, Color::_3PB50, Color::_3PB60, Color::_3PB70, Color::_3PB80; - LUTf Color::_15PB10, Color::_15PB20, Color::_15PB30, Color::_15PB40, Color::_15PB50, Color::_15PB60, Color::_15PB70, Color::_15PB80; - LUTf Color::_05PB40, Color::_05PB50, Color::_05PB60, Color::_05PB70, Color::_05PB80; - LUTf Color::_10B40, Color::_10B50, Color::_10B60, Color::_10B70, Color::_10B80; - LUTf Color::_9B40, Color::_9B50, Color::_9B60, Color::_9B70, Color::_9B80; - LUTf Color::_7B40, Color::_7B50, Color::_7B60, Color::_7B70, Color::_7B80; - LUTf Color::_5B40, Color::_5B50, Color::_5B60, Color::_5B70, Color::_5B80; - LUTf Color::_10YR20, Color::_10YR30, Color::_10YR40, Color::_10YR50, Color::_10YR60, Color::_10YR70, Color::_10YR80, Color::_10YR90; - LUTf Color::_85YR20, Color::_85YR30, Color::_85YR40, Color::_85YR50, Color::_85YR60, Color::_85YR70, Color::_85YR80, Color::_85YR90; - LUTf Color::_7YR30, Color::_7YR40, Color::_7YR50, Color::_7YR60, Color::_7YR70, Color::_7YR80; - LUTf Color::_55YR30, Color::_55YR40, Color::_55YR50, Color::_55YR60, Color::_55YR70, Color::_55YR80, Color::_55YR90; - LUTf Color::_4YR30, Color::_4YR40, Color::_4YR50, Color::_4YR60, Color::_4YR70, Color::_4YR80; - LUTf Color::_25YR30, Color::_25YR40, Color::_25YR50, Color::_25YR60, Color::_25YR70; - LUTf Color::_10R30, Color::_10R40, Color::_10R50, Color::_10R60, Color::_10R70; - LUTf Color::_9R30, Color::_9R40, Color::_9R50, Color::_9R60, Color::_9R70; - LUTf Color::_7R30, Color::_7R40, Color::_7R50, Color::_7R60, Color::_7R70; - LUTf Color::_5R10, Color::_5R20, Color::_5R30; - LUTf Color::_25R10, Color::_25R20, Color::_25R30; - LUTf Color::_10RP10, Color::_10RP20, Color::_10RP30; - LUTf Color::_7G30, Color::_7G40, Color::_7G50, Color::_7G60, Color::_7G70, Color::_7G80; - LUTf Color::_5G30, Color::_5G40, Color::_5G50, Color::_5G60, Color::_5G70, Color::_5G80; - LUTf Color::_25G30, Color::_25G40, Color::_25G50, Color::_25G60, Color::_25G70, Color::_25G80; - LUTf Color::_1G30, Color::_1G40, Color::_1G50, Color::_1G60, Color::_1G70, Color::_1G80; - LUTf Color::_10GY30, Color::_10GY40, Color::_10GY50, Color::_10GY60, Color::_10GY70, Color::_10GY80; - LUTf Color::_75GY30, Color::_75GY40, Color::_75GY50, Color::_75GY60, Color::_75GY70, Color::_75GY80; - LUTf Color::_5GY30, Color::_5GY40, Color::_5GY50, Color::_5GY60, Color::_5GY70, Color::_5GY80; - -#ifdef _DEBUG - MunsellDebugInfo::MunsellDebugInfo() { - reinitValues(); - } - void MunsellDebugInfo::reinitValues() { - maxdhue[0]=maxdhue[1]=maxdhue[2]=maxdhue[3]=0.0f; - maxdhuelum[0]=maxdhuelum[1]=maxdhuelum[2]=maxdhuelum[3]=0.0f; - depass=depassLum=0; - } -#endif - - - void Color::init () { - - int maxindex = 65536; - cachef(maxindex,LUT_CLIP_BELOW); - - gamma2curve(maxindex,LUT_CLIP_BELOW|LUT_CLIP_ABOVE); - - for (int i=0; ieps_max) { - cachef[i] = 327.68*( exp(1.0/3.0 * log((double)i / MAXVALF) )); - } - else { - cachef[i] = 327.68*((kappa*i/MAXVALF+16.0)/116.0); - } - } - - for (int i=0; i-0.00001) { // no fabs, slow! - h = 0.f; - s = 0.f; - } - else { - double h_; - if (l_ <= 0.5) - s = float( (M-m) / (M+m) ); - else - s = float( (M-m) / (2.0-M-m) ); - - if ( var_R == M ) h_ = (var_G - var_B)/C; - else if ( var_G == M ) h_ = 2. + (var_B - var_R)/C; - else h_ = 4. + (var_R - var_G)/C; - h = float(h_ /= 6.0); - - if ( h < 0.f ) h += 1.f; - if ( h > 1.f ) h -= 1.f; - } - } - - double Color::hue2rgb(double p, double q, double t){ - if (t < 0.) t += 6.; - else if( t > 6.) t -= 6.; - - if (t < 1.) return p + (q - p) * t; - else if (t < 3.) return q; - else if (t < 4.) return p + (q - p) * (4. - t); - else return p; - } - - void Color::hsl2rgb (float h, float s, float l, float &r, float &g, float &b) { - - if (s == 0) - r = g = b = 65535.0f * l; // achromatic - else { - double m2; - double h_ = double(h); - double s_ = double(s); - double l_ = double(l); - - if (l <= 0.5f) - m2 = l_ * (1.0 + s_); - else { - m2 = l_ + s_ - l_ * s_; - } - - double m1 = 2.0 * l_ - m2; - - r = float(65535.0 * hue2rgb (m1, m2, h_ * 6.0 + 2.0)); - g = float(65535.0 * hue2rgb (m1, m2, h_ * 6.0)); - b = float(65535.0 * hue2rgb (m1, m2, h_ * 6.0 - 2.0)); - } - } - - void Color::hsl2rgb01 (float h, float s, float l, float &r, float &g, float &b) { - - if (s == 0) - r = g = b = l; // achromatic - else { - double m2; - double h_ = double(h); - double s_ = double(s); - double l_ = double(l); - - if (l <= 0.5f) - m2 = l_ * (1.0 + s_); - else { - m2 = l_ + s_ - l_ * s_; - } - - double m1 = 2.0 * l_ - m2; - - r = float(hue2rgb (m1, m2, h_ * 6.0 + 2.0)); - g = float(hue2rgb (m1, m2, h_ * 6.0)); - b = float(hue2rgb (m1, m2, h_ * 6.0 - 2.0)); - } - } - - void Color::rgb2hsv(float r, float g, float b, float &h, float &s, float &v) { - double var_R = r / 65535.0; - double var_G = g / 65535.0; - double var_B = b / 65535.0; - - double var_Min = min(var_R,var_G,var_B); - double var_Max = max(var_R,var_G,var_B); - double del_Max = var_Max - var_Min; - v = var_Max; - if (del_Max<0.00001 && del_Max>-0.00001) { // no fabs, slow! - h = 0; - s = 0; - } - else { - s = del_Max/var_Max; - - if ( var_R == var_Max ) h = (var_G - var_B)/del_Max; - else if ( var_G == var_Max ) h = 2.0 + (var_B - var_R)/del_Max; - else if ( var_B == var_Max ) h = 4.0 + (var_R - var_G)/del_Max; - h /= 6.0; - - if ( h < 0 ) h += 1; - if ( h > 1 ) h -= 1; - } - } - - void Color::hsv2rgb (float h, float s, float v, float &r, float &g, float &b) { - - float h1 = h*6.f; // sector 0 to 5 - int i = (int)h1; // floor() is very slow, and h1 is always >0 - float f = h1 - i; // fractional part of h - - float p = v * ( 1.f - s ); - float q = v * ( 1.f - s * f ); - float t = v * ( 1.f - s * ( 1.f - f ) ); - - float r1,g1,b1; - - if (i==1) {r1 = q; g1 = v; b1 = p;} - else if (i==2) {r1 = p; g1 = v; b1 = t;} - else if (i==3) {r1 = p; g1 = q; b1 = v;} - else if (i==4) {r1 = t; g1 = p; b1 = v;} - else if (i==5) {r1 = v; g1 = p; b1 = q;} - else /*i==(0|6)*/ {r1 = v; g1 = t; b1 = p;} - - r = ((r1)*65535.0f); - g = ((g1)*65535.0f); - b = ((b1)*65535.0f); - } - - // Function copied for speed concerns - // Not exactly the same as above ; this one return a result in the [0.0 ; 1.0] range - void Color::hsv2rgb01 (float h, float s, float v, float &r, float &g, float &b) { - float h1 = h*6; // sector 0 to 5 - int i = int(h1); - float f = h1 - i; // fractional part of h - - float p = v * ( 1 - s ); - float q = v * ( 1 - s * f ); - float t = v * ( 1 - s * ( 1 - f ) ); - - if (i==1) {r = q; g = v; b = p;} - else if (i==2) {r = p; g = v; b = t;} - else if (i==3) {r = p; g = q; b = v;} - else if (i==4) {r = t; g = p; b = v;} - else if (i==5) {r = v; g = p; b = q;} - else /*(i==0|6)*/ {r = v; g = t; b = p;} - } - - void Color::hsv2rgb (float h, float s, float v, int &r, int &g, int &b) { - - float h1 = h*6; // sector 0 to 5 - int i = floor( h1 ); - float f = h1 - i; // fractional part of h - - float p = v * ( 1 - s ); - float q = v * ( 1 - s * f ); - float t = v * ( 1 - s * ( 1 - f ) ); - - float r1,g1,b1; - - if (i==0) {r1 = v; g1 = t; b1 = p;} - else if (i==1) {r1 = q; g1 = v; b1 = p;} - else if (i==2) {r1 = p; g1 = v; b1 = t;} - else if (i==3) {r1 = p; g1 = q; b1 = v;} - else if (i==4) {r1 = t; g1 = p; b1 = v;} - else if (i==5) {r1 = v; g1 = p; b1 = q;} - - r = (int)( r1 * 65535); - g = (int)( g1 * 65535); - b = (int)( b1 * 65535); - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - void Color::xyz2srgb (float x, float y, float z, float &r, float &g, float &b) { - - //Transform to output color. Standard sRGB is D65, but internal representation is D50 - //Note that it is only at this point that we should have need of clipping color data - - /*float x65 = d65_d50[0][0]*x + d65_d50[0][1]*y + d65_d50[0][2]*z ; - float y65 = d65_d50[1][0]*x + d65_d50[1][1]*y + d65_d50[1][2]*z ; - float z65 = d65_d50[2][0]*x + d65_d50[2][1]*y + d65_d50[2][2]*z ; - - r = sRGB_xyz[0][0]*x65 + sRGB_xyz[0][1]*y65 + sRGB_xyz[0][2]*z65; - g = sRGB_xyz[1][0]*x65 + sRGB_xyz[1][1]*y65 + sRGB_xyz[1][2]*z65; - b = sRGB_xyz[2][0]*x65 + sRGB_xyz[2][1]*y65 + sRGB_xyz[2][2]*z65;*/ - - /*r = sRGBd65_xyz[0][0]*x + sRGBd65_xyz[0][1]*y + sRGBd65_xyz[0][2]*z ; - g = sRGBd65_xyz[1][0]*x + sRGBd65_xyz[1][1]*y + sRGBd65_xyz[1][2]*z ; - b = sRGBd65_xyz[2][0]*x + sRGBd65_xyz[2][1]*y + sRGBd65_xyz[2][2]*z ;*/ - - r = ((sRGB_xyz[0][0]*x + sRGB_xyz[0][1]*y + sRGB_xyz[0][2]*z)) ; - g = ((sRGB_xyz[1][0]*x + sRGB_xyz[1][1]*y + sRGB_xyz[1][2]*z)) ; - b = ((sRGB_xyz[2][0]*x + sRGB_xyz[2][1]*y + sRGB_xyz[2][2]*z)) ; - - } - void Color::xyz2Prophoto (float x, float y, float z, float &r, float &g, float &b) { - r = ((prophoto_xyz[0][0]*x + prophoto_xyz[0][1]*y + prophoto_xyz[0][2]*z)) ; - g = ((prophoto_xyz[1][0]*x + prophoto_xyz[1][1]*y + prophoto_xyz[1][2]*z)) ; - b = ((prophoto_xyz[2][0]*x + prophoto_xyz[2][1]*y + prophoto_xyz[2][2]*z)) ; - } - void Color::Prophotoxyz (float r, float g, float b, float &x, float &y, float &z) { - x = ((xyz_prophoto[0][0]*r + xyz_prophoto[0][1]*g + xyz_prophoto[0][2]*b)) ; - y = ((xyz_prophoto[1][0]*r + xyz_prophoto[1][1]*g + xyz_prophoto[1][2]*b)) ; - z = ((xyz_prophoto[2][0]*r + xyz_prophoto[2][1]*g + xyz_prophoto[2][2]*b)) ; - } - - void Color::rgbxyz (float r, float g, float b, float &x, float &y, float &z, const double xyz_rgb[3][3]) { - x = ((xyz_rgb[0][0]*r + xyz_rgb[0][1]*g + xyz_rgb[0][2]*b)) ; - y = ((xyz_rgb[1][0]*r + xyz_rgb[1][1]*g + xyz_rgb[1][2]*b)) ; - z = ((xyz_rgb[2][0]*r + xyz_rgb[2][1]*g + xyz_rgb[2][2]*b)) ; - } - - void Color::rgbxyz (float r, float g, float b, float &x, float &y, float &z, const float xyz_rgb[3][3]) { - x = ((xyz_rgb[0][0]*r + xyz_rgb[0][1]*g + xyz_rgb[0][2]*b)) ; - y = ((xyz_rgb[1][0]*r + xyz_rgb[1][1]*g + xyz_rgb[1][2]*b)) ; - z = ((xyz_rgb[2][0]*r + xyz_rgb[2][1]*g + xyz_rgb[2][2]*b)) ; - } - - void Color::xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const double rgb_xyz[3][3]) { - //Transform to output color. Standard sRGB is D65, but internal representation is D50 - //Note that it is only at this point that we should have need of clipping color data - - /*float x65 = d65_d50[0][0]*x + d65_d50[0][1]*y + d65_d50[0][2]*z ; - float y65 = d65_d50[1][0]*x + d65_d50[1][1]*y + d65_d50[1][2]*z ; - float z65 = d65_d50[2][0]*x + d65_d50[2][1]*y + d65_d50[2][2]*z ; - - r = sRGB_xyz[0][0]*x65 + sRGB_xyz[0][1]*y65 + sRGB_xyz[0][2]*z65; - g = sRGB_xyz[1][0]*x65 + sRGB_xyz[1][1]*y65 + sRGB_xyz[1][2]*z65; - b = sRGB_xyz[2][0]*x65 + sRGB_xyz[2][1]*y65 + sRGB_xyz[2][2]*z65;*/ - - /*r = sRGBd65_xyz[0][0]*x + sRGBd65_xyz[0][1]*y + sRGBd65_xyz[0][2]*z ; - g = sRGBd65_xyz[1][0]*x + sRGBd65_xyz[1][1]*y + sRGBd65_xyz[1][2]*z ; - b = sRGBd65_xyz[2][0]*x + sRGBd65_xyz[2][1]*y + sRGBd65_xyz[2][2]*z ;*/ - - r = ((rgb_xyz[0][0]*x + rgb_xyz[0][1]*y + rgb_xyz[0][2]*z)) ; - g = ((rgb_xyz[1][0]*x + rgb_xyz[1][1]*y + rgb_xyz[1][2]*z)) ; - b = ((rgb_xyz[2][0]*x + rgb_xyz[2][1]*y + rgb_xyz[2][2]*z)) ; - } - - // same for float - void Color::xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const float rgb_xyz[3][3]) { - r = ((rgb_xyz[0][0]*x + rgb_xyz[0][1]*y + rgb_xyz[0][2]*z)) ; - g = ((rgb_xyz[1][0]*x + rgb_xyz[1][1]*y + rgb_xyz[1][2]*z)) ; - b = ((rgb_xyz[2][0]*x + rgb_xyz[2][1]*y + rgb_xyz[2][2]*z)) ; - } - - void Color::trcGammaBW (float &r, float &g, float &b, float gammabwr, float gammabwg, float gammabwb) { - // correct gamma for black and white image : pseudo TRC curve of ICC profil - b/=65535.0f; - b= pow (max(b,0.0f), gammabwb); - b *=65535.0f; - r/=65535.0f; - r= pow (max(r,0.0f), gammabwr); - r *=65535.0f; - g/=65535.0f; - g= pow (max(g,0.0f), gammabwg); - g *=65535.0f; - } - - /** @brief Compute the B&W constants for the B&W processing and its tool's GUI - * - * @param setting BlackWhite::setting - * @param setting BlackWhite::filter - */ - void Color::computeBWMixerConstants (const Glib::ustring &setting, const Glib::ustring &filter, const Glib::ustring &algo, float &filcor, float &mixerRed, float &mixerGreen, - float &mixerBlue, float mixerOrange, float mixerYellow, float mixerCyan, float mixerPurple, float mixerMagenta, - bool autoc, bool complement, float &kcorec, double &rrm, double &ggm, double &bbm) - { - float somm; - float som = mixerRed+mixerGreen+mixerBlue; - // rM = mixerRed, gM = mixerGreen, bM = mixerBlue ! - //presets - if (setting=="RGB-Abs" || setting=="ROYGCBPM-Abs") - kcorec=som/100.f; - - if (!autoc) { - //if (setting=="RGB-Abs" || setting=="ROYGCBPM-Abs") {} //Keep the RGB mixer values as is! - //else if(setting=="RGB-Rel" || setting=="ROYGCBPM-Rel") {} //Keep the RGB mixer values as is! - if (setting=="NormalContrast") { mixerRed=43.f ; mixerGreen=33.f; mixerBlue=30.f; } - else if(setting=="Panchromatic") { mixerRed=33.3f; mixerGreen=33.3f; mixerBlue=33.3f; } - else if(setting=="HyperPanchromatic") { mixerRed=41.f ; mixerGreen=25.f; mixerBlue=34.f; } - else if(setting=="LowSensitivity") { mixerRed=27.f ; mixerGreen=27.f; mixerBlue=46.f; } - else if(setting=="HighSensitivity") { mixerRed=30.f ; mixerGreen=28.f; mixerBlue=42.f; } - else if(setting=="Orthochromatic") { mixerRed=0.f ; mixerGreen=42.f; mixerBlue=58.f; } - else if(setting=="HighContrast") { mixerRed=40.f ; mixerGreen=34.f; mixerBlue=60.f; } - else if(setting=="Luminance") { mixerRed=30.f ; mixerGreen=59.f; mixerBlue=11.f; } - else if(setting=="Landscape") { mixerRed=66.f ; mixerGreen=24.f; mixerBlue=10.f; } - else if(setting=="Portrait") { mixerRed=54.f ; mixerGreen=44.f; mixerBlue=12.f; } - else if(setting=="InfraRed") { mixerRed=-40.f; mixerGreen=200.f; mixerBlue=-17.f; } - } - - rrm=mixerRed; - ggm=mixerGreen; - bbm=mixerBlue; - - somm=mixerRed+mixerGreen+mixerBlue; - mixerRed=mixerRed/somm; mixerGreen=mixerGreen/somm; mixerBlue=mixerBlue/somm; - float koymcp=0.f; - - if(setting=="ROYGCBPM-Abs" || setting=="ROYGCBPM-Rel") { - float obM=0.f; - float ogM=0.f; - float orM=0.f; - - float ybM=0.f; - float yrM=0.f; - float ygM=0.f; - - float mgM=0.f; - float mrM=0.f; - float mbM=0.f; - - float pgM=0.f; - float prM=0.f; - float pbM=0.f; - - float crM=0.f; - float cgM=0.f; - float cbM=0.f; - //printf("mixred=%f\n",mixerRed); - - float fcompl = 1.f; - if(complement && algo=="SP") fcompl = 3.f;//special - else if(complement && algo=="LI") fcompl = 1.5f;//linear - // ponderate filters: report to R=G=B=33 - // I ponder RGB channel, not only orange or yellow or cyan, etc...it's my choice ! - if(mixerOrange != 33) { - if (algo=="SP") {//special - if (mixerOrange >= 33) orM = fcompl*(mixerOrange*0.67f - 22.11f)/100.f; else orM = fcompl*(-0.3f*mixerOrange +9.9f)/100.f; - if (mixerOrange >= 33) ogM = fcompl*(-0.164f*mixerOrange+5.412f)/100.f; else ogM = fcompl*(0.4f*mixerOrange-13.2f)/100.f; - } - else if (algo=="LI") {//linear - orM = fcompl*(mixerOrange - 33.f)/100.f; - ogM = fcompl*(0.5f*mixerOrange-16.5f)/100.f; - } - if(complement) obM =(-0.492f*mixerOrange+16.236f)/100.f; - mixerRed += orM; - mixerGreen += ogM; - mixerBlue += obM; - koymcp += (orM+ogM+obM); - // printf("mixred+ORange=%f\n",mixerRed); - - } - if(mixerYellow != 33) { - if (algo=="SP") yrM = fcompl*(-0.134f*mixerYellow+4.422f)/100.f;//22.4 - else if (algo=="LI")yrM = fcompl*(0.5f*mixerYellow-16.5f)/100.f;//22.4 - ygM = fcompl*(0.5f *mixerYellow-16.5f )/100.f; - if(complement) ybM =(-0.492f*mixerYellow+16.236f)/100.f; - mixerRed += yrM; - mixerGreen += ygM; - mixerBlue += ybM; - koymcp += (yrM+ygM+ybM); - } - if(mixerMagenta != 33) { - if (algo=="SP"){ - if(mixerMagenta >= 33) mrM = fcompl*( 0.67f *mixerMagenta-22.11f)/100.f; else mrM = fcompl*(-0.3f*mixerMagenta +9.9f)/100.f; - if(mixerMagenta >= 33) mbM = fcompl*(-0.164f*mixerMagenta+5.412f)/100.f; else mbM = fcompl*( 0.4f*mixerMagenta-13.2f)/100.f; - } - else if (algo=="LI"){ - mrM = fcompl*(mixerMagenta-33.f)/100.f; - mbM = fcompl*(0.5f*mixerMagenta-16.5f)/100.f; - } - if(complement) mgM =(-0.492f*mixerMagenta+16.236f)/100.f; - mixerRed += mrM; - mixerGreen += mgM; - mixerBlue += mbM; - koymcp += (mrM+mgM+mbM); - } - if(mixerPurple != 33) { - if (algo=="SP") prM = fcompl*(-0.134f*mixerPurple+4.422f)/100.f; - else if (algo=="LI")prM = fcompl*(0.5f*mixerPurple-16.5f)/100.f; - pbM = fcompl*(0.5f*mixerPurple-16.5f)/100.f; - if(complement) pgM = (-0.492f*mixerPurple+16.236f)/100.f; - mixerRed += prM; - mixerGreen += pgM; - mixerBlue += pbM; - koymcp += (prM+pgM+pbM); - } - if(mixerCyan != 33) { - if (algo=="SP")cgM = fcompl*(-0.134f*mixerCyan +4.422f)/100.f; - else if (algo=="LI")cgM = fcompl*(0.5f*mixerCyan -16.5f)/100.f; - cbM = fcompl*(0.5f*mixerCyan-16.5f)/100.f; - if(complement) crM = (-0.492f*mixerCyan+16.236f)/100.f; - mixerRed += crM; - mixerGreen += cgM; - mixerBlue += cbM; - koymcp += (crM+cgM+cbM); - } - } - if(setting=="ROYGCBPM-Abs") - kcorec = koymcp+som/100.f; - //Color filters - float filred,filgreen,filblue; - filred=1.f;filgreen=1.f;filblue=1.f;filcor=1.f; - if (filter=="None") {filred=1.f; filgreen=1.f; filblue=1.f; filcor=1.f;} - else if (filter=="Red") {filred=1.f; filgreen=0.05f;filblue=0.f; filcor=1.08f;} - else if (filter=="Orange") {filred=1.f; filgreen=0.6f; filblue=0.f; filcor=1.35f;} - else if (filter=="Yellow") {filred=1.f; filgreen=1.f; filblue=0.05f;filcor=1.23f;} - else if (filter=="YellowGreen") {filred=0.6f; filgreen=1.f; filblue=0.3f;filcor=1.32f;} - else if (filter=="Green") {filred=0.2f; filgreen=1.f; filblue=0.3f;filcor=1.41f;} - else if (filter=="Cyan") {filred=0.05f;filgreen=1.f; filblue=1.f; filcor=1.23f;} - else if (filter=="Blue") {filred=0.f; filgreen=0.05f;filblue=1.f; filcor=1.20f;} - else if (filter=="Purple") {filred=1.f; filgreen=0.05f;filblue=1.f; filcor=1.23f;} - mixerRed = mixerRed * filred; - mixerGreen = mixerGreen * filgreen; - mixerBlue = mixerBlue * filblue; - - mixerRed = filcor*mixerRed / (mixerRed + mixerGreen + mixerBlue); - mixerGreen = filcor*mixerGreen / (mixerRed + mixerGreen + mixerBlue); - mixerBlue = filcor*mixerBlue / (mixerRed + mixerGreen + mixerBlue); - - if(filter!="None") { - som = mixerRed+mixerGreen+mixerBlue; - if(setting=="RGB-Abs" || setting=="ROYGCBPM-Abs") kcorec = kcorec*som; - } - - } - - void Color::interpolateRGBColor (const float balance, const float r1, const float g1, const float b1, const float r2, const float g2, const float b2, int toDo, const double xyz_rgb[3][3], const double rgb_xyz[3][3], float &ro, float &go, float &bo) { - float X1, Y1, Z1, X2, Y2, Z2, X, Y, Z; - float L1, L2, a_1, b_1, a_2, b_2, a, b; - float c1, c2, h1, h2; - float RR,GG,BB; - float Lr; - - // converting color 1 to Lch - Color::rgbxyz(r1, g1, b1, X1, Y1, Z1, xyz_rgb); - Color::XYZ2Lab(X1, Y1, Z1, L1, a_1, b_1); - Color::Lab2Lch(a_1, b_1, c1, h1); - Lr=L1/327.68f;//for gamutlch - //gamut control on r1 g1 b1 - #ifndef NDEBUG - bool neg=false; - bool more_rgb=false; - - //gamut control : Lab values are in gamut - Color::gamutLchonly(h1,Lr,c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f, neg, more_rgb); - #else - Color::gamutLchonly(h1,Lr,c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f); - #endif - - L1=Lr*327.68f; - - // converting color 2 to Lch - Color::rgbxyz(r2, g2, b2, X2, Y2, Z2, xyz_rgb); - Color::XYZ2Lab(X2, Y2, Z2, L2, a_2, b_2); - Color::Lab2Lch(a_2, b_2, c2, h2); - - Lr=L2/327.68f;//for gamutlch - //gamut control on r2 g2 b2 - #ifndef NDEBUG - neg=false; - more_rgb=false; - //gamut control : Lab values are in gamut - Color::gamutLchonly(h2,Lr,c2, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f, neg, more_rgb); - #else - Color::gamutLchonly(h2,Lr,c2, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f); - #endif - L2=Lr*327.68f; - - // interpolating Lch values - if (toDo & CHANNEL_LIGHTNESS) { L1 = L1 + (L2-L1)*balance;if(L1<0.f) L1=0.f;}//do not allow negative L - if (toDo & CHANNEL_CHROMATICITY) {c1 = c1 + (c2-c1)*balance;if(c1<0.f) c1=0.f; if(c1>180.f) c1=180.f;}//limit C to reasonable value - if (toDo & CHANNEL_HUE) h1 = interpolatePolarHue_PI(h1, h2, balance); - - // here I have put gamut control with gamutlchonly on final process - Lr=L1/327.68f;//for gamutlch - #ifndef NDEBUG - neg=false; - more_rgb=false; - //gamut control : Lab values are in gamut - Color::gamutLchonly(h1,Lr,c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f, neg, more_rgb); - #else - //gamut control : Lab values are in gamut - Color::gamutLchonly(h1,Lr,c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f); - #endif - //convert CH ==> ab - L1=Lr*327.68f; - - // converting back to rgb - Color::Lch2Lab(c1, h1, a, b); - Color::Lab2XYZ(L1, a, b, X, Y, Z); - Color::xyz2rgb(X, Y, Z, ro, go, bo, rgb_xyz); - } - - - void Color::interpolateRGBColor (float realL, float iplow, float iphigh, int algm, const float balance, int twoc, int metchrom, - bool chr, bool lum, float chromat, float luma, const float r1, const float g1, const float b1, - const float xl, const float yl, const float zl, const float x2, const float y2, const float z2, - int toDo, const double xyz_rgb[3][3], const double rgb_xyz[3][3], float &ro, float &go, float &bo) - { - float X1, Y1, Z1, X2, Y2, Z2, X, Y, Z,XL,YL,ZL; - float L1, L2, LL, a_1, b_1, a_2, b_2, a, b,a_L,b_L; - float c1, c2, h1, h2,cL,hL; - float RR,GG,BB; - float Lr; - float slc=0.f; - float hh=0.f; - float ll=0.f; - float sh=0.f; - bool LCH=false; - - float ha,hb,hc,ba; - float c_1,h_1; - // converting color 1 to Lab (image) - Color::rgbxyz(r1, g1, b1, X1, Y1, Z1, xyz_rgb); - if(algm == 1) {//use H interpolate - Color::XYZ2Lab(X1, Y1, Z1, L1, a_1, b_1); - //Color::Lab2Lch(a_1, b_1, c_1, h_1) ; - } - // converting color l lab(low) first color - if(twoc==0) { // 2 colours - //Color::rgbxyz(rl, gl, bl, XL, YL, ZL, xyz_rgb); - XL=xl; - YL=yl; - ZL=zl; - if(algm <= 1) {//use H interpolate - Color::XYZ2Lab(XL, YL, ZL, LL, a_L, b_L); - } - } - - // converting color 2 to lab (universal or high) - X2=x2; - Y2=y2; - Z2=z2; - float c_2,h_2; - if(algm == 1 ) { - Color::XYZ2Lab(X2, Y2, Z2, L2, a_2, b_2); - //Color::Lab2Lch(a_2, b_2, c_2, h_2) ; - } - float bal,balH,cal,calH,calm; - bal=balH=balance; - cal=calH=calm=1.f-chromat; - float med=(iphigh+iplow)/2.f; - float medH=(iphigh+iplow)/2.f; - float medL=(iphigh+iplow)/2.f; - - med=1.f;medH=0.f;//new algo for 2 colors - float calan; - calan=chromat; - - float calby; - calby=luma; - - if(twoc==0) { // 2 colours - calan=chromat; - - //calculate new balance in function of (arbitrary) "med".. I hope no error !! - if (realL > iplow && realL<=med) bal = realL*balance/(iplow-med) - med*balance/(iplow-med); - else if (realL <= iplow) bal = realL*balance/iplow; - - if (realL > medH && realL <= iphigh) balH = realL*balance/(iphigh-medH) - medH*balance/(iphigh-medH); - else if (realL > iphigh) balH = realL*balance*(iphigh-1.f) - balance*(iphigh-1.f); - - //calculate new balance chroma - if (realL > iplow && realL<=med) cal = realL*calan/(iplow-med) - med*calan/(iplow-med); - else if (realL <= iplow) cal = realL*calan/iplow; - - if (realL > medH && realL <= iphigh) calH = realL*calan/(iphigh-medH) - medH*calan/(iphigh-medH); - else if (realL > iphigh) calH = realL*calan;//*(iphigh-1.f) - calan*(iphigh-1.f);//it is better without transition in highlight - } - - float hX=0.f; - float hLL,hH,ccL,ccH,llH,aaH,bbH; - - if(algm <=1){ - if(twoc==0 && metchrom==3) { // 2 colours only with special "ab" - if(algm==1) { - aaH=a_1 + (a_2-a_1)*calH;bbH=b_1 + (b_2-b_1)*calH;//pass to line after - a_1=aaH + (a_L-aaH)*cal*balance;b_1=bbH + (b_L-bbH)*cal*balance; - } - } - else if(twoc==1) { - if(metchrom==0) { - a_1=a_1 + (a_2-a_1)*balance; - b_1=b_1 + (b_2-b_1)*balance; - } - else if(metchrom==1){ - a_1=a_1 + (a_2-a_1)*calan*balance; - b_1=b_1 + (b_2-b_1)*calan*balance; - } - else if(metchrom==2) { - a_1=a_1 + (a_2-a_1)*calan*balance; - b_1=b_1 + (b_2-b_1)*calby*balance; - } - } - } - else - h1=hX; - - Color::Lab2XYZ(L1, a_1, b_1, X, Y, Z); - - Color::xyz2rgb(X, Y, Z, ro, go, bo, rgb_xyz);// ro go bo in gamut - } - - void Color::calcGamma (double pwr, double ts, int mode, int imax, double &gamma0, double &gamma1, double &gamma2, double &gamma3, double &gamma4, double &gamma5) { - //from Dcraw (D.Coffin) - int i; - double g[6], bnd[2]={0,0}; - - g[0] = pwr; - g[1] = ts; - g[2] = g[3] = g[4] = 0; - bnd[g[1] >= 1] = 1; - if (g[1] && (g[1]-1)*(g[0]-1) <= 0) { - for (i=0; i < 48; i++) { - g[2] = (bnd[0] + bnd[1])/2; - if (g[0]) - bnd[(pow(g[2]/g[1],-g[0]) - 1)/g[0] - 1/g[2] > -1] = g[2]; - else - bnd[g[2]/exp(1-1/g[2]) < g[1]] = g[2]; - } - g[3] = g[2] / g[1]; - if (g[0]) g[4] = g[2] * (1/g[0] - 1); - } - if (g[0]) - g[5] = 1 / (g[1]*SQR(g[3])/2 - g[4]*(1 - g[3]) + (1 - pow(g[3],1+g[0]))*(1 + g[4])/(1 + g[0])) - 1; - else - g[5] = 1 / (g[1]*SQR(g[3])/2 + 1 - g[2] - g[3] - g[2]*g[3]*(log(g[3]) - 1)) - 1; - if (!mode--) { - gamma0=g[0];gamma1=g[1];gamma2=g[2];gamma3=g[3];gamma4=g[4];gamma5=g[5]; - return; - } - } - - void Color::Lab2XYZ(float L, float a, float b, float &x, float &y, float &z) { - float LL=L/327.68f; - float aa=a/327.68f; - float bb=b/327.68f; - float fy = (0.00862069f * LL) + 0.137932f; // (L+16)/116 - float fx = (0.002f * aa) + fy; - float fz = fy - (0.005f * bb); - x = 65535.0f*f2xyz(fx)*D50x; - z = 65535.0f*f2xyz(fz)*D50z; - y=(LL>epskap) ? 65535.0f*fy*fy*fy : 65535.0f*LL/kappa; - } - -#ifdef __SSE2__ - void Color::Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat &z) { - vfloat c327d68 = F2V(327.68f); - L /= c327d68; - a /= c327d68; - b /= c327d68; - vfloat fy = F2V(0.00862069f) * L + F2V(0.137932f); - vfloat fx = F2V(0.002f) * a + fy; - vfloat fz = fy - (F2V(0.005f) * b); - vfloat c65535 = F2V(65535.f); - x = c65535*f2xyz(fx)*F2V(D50x); - z = c65535*f2xyz(fz)*F2V(D50z); - vfloat res1 = fy*fy*fy; - vfloat res2 = L / F2V(kappa); - y = vself(vmaskf_gt(L, F2V(epskap)), res1, res2); - y *= c65535; - } -#endif // __SSE2__ - - void Color::XYZ2Lab(float X, float Y, float Z, float &L, float &a, float &b) { - - float x = X/D50x; - float z = Z/D50z; - float y= Y; - float fx,fy,fz; - - fx = (x<=65535.0f ? cachef[x] : (327.68f*xcbrtf(x/MAXVALF))); - fy = (y<=65535.0f ? cachef[y] : (327.68f*xcbrtf(y/MAXVALF))); - fz = (z<=65535.0f ? cachef[z] : (327.68f*xcbrtf(z/MAXVALF))); - - L = (116.0f * fy - 5242.88f); //5242.88=16.0*327.68; - a = (500.0f * (fx - fy) ); - b = (200.0f * (fy - fz) ); - } - - void Color::Lab2Yuv(float L, float a, float b, float &Y, float &u, float &v) { - float fy = (0.00862069 * L/327.68) + 0.137932; // (L+16)/116 - float fx = (0.002 * a/327.68) + fy; - float fz = fy - (0.005 * b/327.68); - float LL=L/327.68; - - float X = 65535.0*f2xyz(fx)*D50x; - // Y = 65535.0*f2xyz(fy); - float Z = 65535.0*f2xyz(fz)*D50z; - Y=(LL/327.68f>epskap) ? 65535.0*fy*fy*fy : 65535.0*LL/kappa; - - u = 4.0*X/(X+15*Y+3*Z)-u0; - v = 9.0*Y/(X+15*Y+3*Z)-v0; - } - - void Color::Yuv2Lab(float Yin, float u, float v, float &L, float &a, float &b, double wp[3][3]) { - float u1 = u + u0; - float v1 = v + v0; - - float Y = Yin; - float X = (9*u1*Y)/(4*v1*D50x); - float Z = (12 - 3*u1 - 20*v1)*Y/(4*v1*D50z); - - gamutmap(X,Y,Z,wp); - - float fx = (X<=65535.0 ? cachef[X] : (327.68*exp(log(X/MAXVALF)/3.0 ))); - float fy = (Y<=65535.0 ? cachef[Y] : (327.68*exp(log(Y/MAXVALF)/3.0 ))); - float fz = (Z<=65535.0 ? cachef[Z] : (327.68*exp(log(Z/MAXVALF)/3.0 ))); - - L = (116.0 * fy - 5242.88); //5242.88=16.0*327.68; - a = (500.0 * (fx - fy) ); - b = (200.0 * (fy - fz) ); - } - - void Color::Lab2Lch(float a, float b, float &c, float &h) { - c = (sqrtf(a*a+b*b))/327.68f; - h = xatan2f(b, a); - } - - void Color::Lch2Lab(float c, float h, float &a, float &b) { - float2 sincosval = xsincosf(h); - a = 327.68f * c * sincosval.y; - b = 327.68f * c * sincosval.x; - } - - void Color::Luv2Lch(float u, float v, float &c, float &h) { - c = sqrtf(u*u+v*v); - h = xatan2f(v, u); //WARNING: should we care of division by zero here? - if (h < 0.f) - h += 1.f; - } - - void Color::Lch2Luv(float c, float h, float &u, float &v) { - float2 sincosval = xsincosf(h); - u = c * sincosval.x; - v = c * sincosval.y; - } - - // NOT TESTED - void Color::XYZ2Luv (float X, float Y, float Z, float &L, float &u, float &v) { - - X /= 65535.f; - Y /= 65535.f; - Z /= 65535.f; - - if (Y > float(eps)) - L = 116.f * pow(Y, 1.f/3.f) -16.f; - else - L = float(kappa) * Y; - u = 13.f * L * float(u0); - v = 13.f * L * float(v0); - } - - // NOT TESTED - void Color::Luv2XYZ (float L, float u, float v, float &X, float &Y, float &Z) { - if (L > float(epskap)) { - float t = (L+16.f) / 116.f; - Y = t*t*t; - } - else - Y = L/float(kappa); - - float a = ((52.f*L) / (u+13.f*L*float(u0)) -1.f) / 3.f; - float d = Y * (((39*L) / (v+13*float(v0))) -5.f); - float b = -5.f*Y; - X = (d-b) / (a+1.f/3.f); - - Z = X*a+b; - - X *= 65535.f; - Y *= 65535.f; - Z *= 65535.f; - } - - /* - * Gamut mapping algorithm - * Copyright (c) 2010-2011 Emil Martinec - * - * Solutions to scaling u and v to XYZ paralleliped boundaries - * Some equations: - * - * fu(X,Y,Z) = 4 X/(X + 15 Y + 3 Z); - * fv(X,Y,Z) = 9 Y/(X + 15 Y + 3 Z); - * - * take the plane spanned by X=a*Xr+b*Xg+c*Xb etc with one of a,b,c equal to 0 or 1, - * and itersect with the line u0+lam*u, or in other words solve - * - * u0+lam*u=fu(X,Y,Z) - * v0+lam*v=fv(X,Y,Z) - * - * The value of lam is the scale factor that takes the color to the gamut boundary - * columns of the matrix p=xyz_rgb are RGB tristimulus primaries in XYZ - * c is the color fixed on the boundary; and m=0 for c=0, m=1 for c=255 - */ - void Color::gamutmap(float &X, float &Y, float &Z, const double p[3][3]) - { - float u = 4*X/(X+15*Y+3*Z)-u0; - float v = 9*Y/(X+15*Y+3*Z)-v0; - - float lam[3][2]; - float lam_min = 1.0; - - for (int c=0; c<3; c++) - for (int m=0; m<2; m++) { - - int c1=(c+1)%3; - int c2=(c+2)%3; - - lam[c][m] = (-(p[0][c1]*p[1][c]*((-12 + 3*u0 + 20*v0)*Y + 4*m*65535*v0*p[2][c2])) + - p[0][c]*p[1][c1]*((-12 + 3*u0 + 20*v0)*Y + 4*m*65535*v0*p[2][c2]) - - 4*v0*p[0][c1]*(Y - m*65535*p[1][c2])*p[2][c] + 4*v0*p[0][c]*(Y - m*65535*p[1][c2])*p[2][c1] - - (4*m*65535*v0*p[0][c2] - 9*u0*Y)*(p[1][c1]*p[2][c] - p[1][c]*p[2][c1])); - - lam[c][m] /= (3*u*Y*(p[0][c1]*p[1][c] - p[1][c1]*(p[0][c] + 3*p[2][c]) + 3*p[1][c]*p[2][c1]) + - 4*v*(p[0][c1]*(5*Y*p[1][c] + m*65535*p[1][c]*p[2][c2] + Y*p[2][c] - m*65535*p[1][c2]*p[2][c]) - - p[0][c]*(5*Y*p[1][c1] + m*65535*p[1][c1]*p[2][c2] + Y*p[2][c1] - m*65535*p[1][c2]*p[2][c1]) + - m*65535*p[0][c2]*(p[1][c1]*p[2][c] - p[1][c]*p[2][c1]))); - - if (lam[c][m]0) lam_min=lam[c][m]; - - } - - u = u*lam_min + u0; - v = v*lam_min + v0; - - X = (9*u*Y)/(4*v); - Z = (12 - 3*u - 20*v)*Y/(4*v); - } - - void Color::skinred ( double J, double h, double sres, double Sp, float dred, float protect_red, int sk, float rstprotection, float ko, double &s) - { - float factorskin, factorsat,factor, factorskinext, interm; - float scale = 100.0f/100.1f;//reduction in normal zone - float scaleext=1.0f;//reduction in transition zone - float protect_redh; - float deltaHH=0.3f;//HH value transition : I have choice 0.3 radians - float HH; - bool doskin=false; - //rough correspondence between h (JC) and H (lab) that has relatively little importance because transitions that blur the correspondence is not linear - if ((float)h>8.6f && (float)h<=74.f ) {HH=(1.15f/65.4f)*(float)h-0.0012f; doskin=true;}//H > 0.15 H<1.3 - else if((float)h>0.f && (float)h<=8.6f ) {HH=(0.19f/8.6f )*(float)h-0.04f; doskin=true;}//H>-0.04 H < 0.15 - else if((float)h>355.f && (float)h<=360.f) {HH=(0.11f/5.0f )*(float)h-7.96f; doskin=true;}//H>-0.15 <-0.04 - else if((float)h>74.f && (float)h<95.f ) {HH=(0.30f/21.0f)*(float)h+0.24285f; doskin=true;}//H>1.3 H<1.6 - - if(doskin) - { - float chromapro=sres/Sp; - if(sk==1){//in C mode to adapt dred to J - if (J<16.0) dred = 40.0f; - else if(J<22.0) dred = (4.1666f)*(float)J -26.6f; - else if(J<60.0) dred = 55.0f; - else if(J<70.0) dred = -1.5f*(float)J +145.0f; - else dred = 40.0f; - } - if(chromapro>0.0) Color::scalered ( rstprotection, chromapro, 0.0, HH, deltaHH, scale, scaleext);//Scale factor - if(chromapro>1.0) {interm=(chromapro-1.0f)*100.0f; - factorskin= 1.0f+(interm*scale)/100.0f; - factorskinext=1.0f+(interm*scaleext)/100.0f;} - else { - factorskin= chromapro ; - factorskinext= chromapro ; - } - factorsat=chromapro; - factor=factorsat; - Color::transitred ( HH, s, dred, factorskin, protect_red, factorskinext, deltaHH, factorsat, factor); //transition - s*=factor; - } - else s=ko*sres; - - } - void Color::skinredfloat ( float J, float h, float sres, float Sp, float dred, float protect_red, int sk, float rstprotection, float ko, float &s) - { - float HH; - bool doskin=false; - //rough correspondence between h (JC) and H (lab) that has relatively little importance because transitions that blur the correspondence is not linear - if ((float)h>8.6f && (float)h<=74.f ) {HH=(1.15f/65.4f)*(float)h-0.0012f; doskin=true;}//H > 0.15 H<1.3 - else if((float)h>0.f && (float)h<=8.6f ) {HH=(0.19f/8.6f )*(float)h-0.04f; doskin=true;}//H>-0.04 H < 0.15 - else if((float)h>355.f && (float)h<=360.f) {HH=(0.11f/5.0f )*(float)h-7.96f; doskin=true;}//H>-0.15 <-0.04 - else if((float)h>74.f && (float)h<95.f ) {HH=(0.30f/21.0f)*(float)h+0.24285f; doskin=true;}//H>1.3 H<1.6 - - if(doskin) - { - float factorskin, factorsat,factor, factorskinext; - float protect_redh; - float deltaHH=0.3f;//HH value transition : I have choice 0.3 radians - float chromapro=sres/Sp; - if(sk==1){//in C mode to adapt dred to J - if (J<16.0) dred = 40.0f; - else if(J<22.0) dred = (4.1666f)*(float)J -26.6f; - else if(J<60.0) dred = 55.0f; - else if(J<70.0) dred = -1.5f*(float)J +145.0f; - else dred = 40.0f; - } - if(chromapro>1.0) { - float scale = 0.999000999f; // 100.0f/100.1f; reduction in normal zone - float scaleext=1.0f;//reduction in transition zone - Color::scalered ( rstprotection, chromapro, 0.0, HH, deltaHH, scale, scaleext);//Scale factor - float interm=(chromapro-1.0f); - factorskin= 1.0f+(interm*scale); - factorskinext=1.0f+(interm*scaleext); - } - else { - factorskin= chromapro ; - factorskinext= chromapro ; - } - factorsat=chromapro; - factor=factorsat; - Color::transitred ( HH, s, dred, factorskin, protect_red, factorskinext, deltaHH, factorsat, factor); //transition - s*=factor; - } - else s=ko*sres; - - } - - - - - - - void Color::scalered ( const float rstprotection, const float param, const float limit, const float HH, const float deltaHH, float &scale, float &scaleext) - { - if(rstprotection<99.9999f) { - if(param > limit) - scale = rstprotection/100.1f; - if((HH< (1.3f+deltaHH) && HH >=1.3f)) - // scaleext=HH*(1.0f-scale)/deltaHH + 1.0f - (1.3f+deltaHH)*(1.0f-scale)/deltaHH; //transition for Hue (red - yellow) - // optimized formula - scaleext=(HH*(1.0f-scale) + deltaHH - (1.3f+deltaHH)*(1.0f-scale))/deltaHH; //transition for Hue (red - yellow) - else if((HH< 0.15f && HH >(0.15f-deltaHH))) - // scaleext=HH*(scale-1.0f)/deltaHH + 1.0f - (0.15f-deltaHH)*(scale-1.0f)/deltaHH; //transition for hue (red purple) - // optimized formula - scaleext=(HH*(scale-1.0f) + deltaHH - (0.15f-deltaHH)*(scale-1.0f))/deltaHH; //transition for hue (red purple) - } - } - - void Color::transitred (const float HH, float const Chprov1, const float dred, const float factorskin, const float protect_red, const float factorskinext, const float deltaHH, const float factorsat, float &factor) - { - if(HH>=0.15f && HH<1.3f) { - if (Chprov1(0.15f-deltaHH) || HH<(1.3f+deltaHH) ) { - if (Chprov1 < dred) - factor = factorskinext;// C=dred=55 => real max of skin tones - else if (Chprov1 < (dred+protect_red))// transition - // factor = (factorsat-factorskinext)/protect_red*Chprov1+factorsat-(dred+protect_red)*(factorsat-factorskinext)/protect_red; - // optimized formula - factor = ((factorsat-factorskinext)*Chprov1 + factorsat*protect_red - (dred+protect_red)*(factorsat-factorskinext))/protect_red; - } - } - - /* - * AllMunsellLch correction - * Copyright (c) 2012 Jacques Desmis - * - * This function corrects the color (hue) for changes in chromaticity and luminance - * to use in a "for" or "do while" statement - * - * Parameters: - * bool lumaMuns : true => luminance correction (for delta L > 10) and chroma correction ; false : only chroma - * float Lprov1 , Loldd : luminance after and before - * float HH: hue before - * float Chprov1, CC : chroma after and before - * float coorectionHuechroma : correction Hue for chromaticity (saturation) - * float correctlum : correction Hue for luminance (brigtness, contrast,...) - * MunsellDebugInfo* munsDbgInfo: (Debug target only) object to collect information. - */ -#ifdef _DEBUG - void Color::AllMunsellLch(bool lumaMuns, float Lprov1,float Loldd,float HH,float Chprov1,float CC,float &correctionHuechroma,float &correctlum, MunsellDebugInfo* munsDbgInfo) -#else - void Color::AllMunsellLch(bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHuechroma, float &correctlum) -#endif - { - - bool contin1,contin2; - float correctionHue=0.0,correctionHueLum=0.0; - bool correctL; - if(CC >= 6.0 && CC < 140) { //if C > 140 we say C=140 (only in Prophoto ...with very large saturation) - static const float huelimit[8]={-2.48,-0.55,0.44,1.52,1.87,3.09,-0.27,0.44};//limits hue of blue-purple, red-yellow, green-yellow, red-purple - if (Chprov1 > 140.f) - Chprov1=139.f; //limits of LUTf - if (Chprov1 < 6.f) - Chprov1=6.f; - for(int zo=1;zo<=4;zo++) { - if(HH>huelimit[2*zo-2] && HHmaxdhue[idx] = MAX(munsDbgInfo->maxdhue[idx], absCorrectionHue); -} - } - if(absCorrectionHue > 0.45) -#pragma omp atomic - munsDbgInfo->depass++; //verify if no bug in calculation -#endif - correctionHuechroma=correctionHue; //preserve - if(lumaMuns) { - float correctlumprov=0.f; - float correctlumprov2=0.f; - if(correctL) { - //for Munsell luminance correction - correctlumprov=correctionHueLum; - contin1=true; - correctL=false; - } - correctionHueLum=0.0; - correctionHue=0.0; - if(fabs(Lprov1-Loldd) > 6.0) { - // correction if delta L significative..Munsell luminance - MunsellLch (Loldd, HH,Chprov1, Chprov1, correctionHue, zo, correctionHueLum, correctL); - - if(correctL) { - correctlumprov2=correctionHueLum; - contin2=true; - correctL=false; - } - correctionHueLum=0.0; - - if(contin1==true && contin2==true) - correctlum=correctlumprov2-correctlumprov; -#ifdef _DEBUG - float absCorrectLum = fabs(correctlum); - if(correctlum !=0.0) { - int idx=zo-1; -#pragma omp critical (maxdhuelum) -{ - munsDbgInfo->maxdhuelum[idx] = MAX(munsDbgInfo->maxdhuelum[idx],absCorrectLum); -} - } - if(absCorrectLum > 0.35) -#pragma omp atomic - munsDbgInfo->depassLum++; //verify if no bug in calculation -#endif - } - } - } - } - - } - -#ifdef _DEBUG - if (correctlum < -0.35f) correctlum =-0.35f; - else if(correctlum > 0.35f) correctlum = 0.35f; - if (correctionHuechroma<-0.45f) correctionHuechroma=-0.45f; - else if(correctionHuechroma> 0.45f) correctionHuechroma= 0.45f; -#endif - - } - - /* - * GamutLchonly correction - * Copyright (c)2012 Jacques Desmis and Jean-Christophe Frisch - * - * This function puts the data (Lab) in the gamut of "working profile": - * it returns the corrected values of the chromaticity and luminance - * - * float HH : hue - * float Lprov1 : input luminance value, sent back corrected - * float Chprov1: input chroma value, sent back corrected - * float R,G,B : red, green and blue value of the corrected color - * double wip : working profile - * bool isHLEnabled : if "highlight reconstruction " is enabled - * float coef : a float number between [0.95 ; 1.0[... the nearest it is from 1.0, the more precise it will be... and the longer too as more iteration will be necessary) - * bool neg and moreRGB : only in DEBUG mode to calculate iterations for negatives values and > 65535 - */ -#ifdef _DEBUG - void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb) -#else - void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef) -#endif - { - const float ClipLevel = 65535.0f; - bool inGamut; -#ifdef _DEBUG - neg=false, more_rgb=false; -#endif - float2 sincosval = xsincosf(HH); - do { - inGamut=true; - - //Lprov1=LL; - float aprov1=Chprov1*sincosval.y; - float bprov1=Chprov1*sincosval.x; - - //conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction - float fy = (0.00862069f *Lprov1 )+ 0.137932f; - float fx = (0.002f * aprov1) + fy; - float fz = fy - (0.005f * bprov1); - - float x_ = 65535.0f * f2xyz(fx)*D50x; - // float y_ = 65535.0f * f2xyz(fy); - float z_ = 65535.0f * f2xyz(fz)*D50z; - float y_=(Lprov1>epskap) ? 65535.0*fy*fy*fy : 65535.0*Lprov1/kappa; - - xyz2rgb(x_,y_,z_,R,G,B,wip); - - // gamut control before saturation to put Lab values in future gamut, but not RGB - if (R<0.0f || G<0.0f || B<0.0f) { -#ifdef _DEBUG - neg=true; -#endif - if (Lprov1 < 0.1f) Lprov1 = 0.1f; - //gamut for L with ultra blue : we can improve the algorithm ... thinner, and other color ??? - if(HH < -0.9f && HH > -1.55f ) {//ultra blue - if(Chprov1 > 160.f) if (Lprov1 < 5.f) Lprov1 = 5.f;//very very very very high chroma - if(Chprov1 > 140.f) if (Lprov1 < 3.5f) Lprov1 = 3.5f; - if(Chprov1 > 120.f) if (Lprov1 < 2.f) Lprov1 = 2.f; - if(Chprov1 > 105.f) if (Lprov1 < 1.f) Lprov1 = 1.f; - if(Chprov1 > 90.f) if (Lprov1 < 0.7f) Lprov1 = 0.7f; - if(Chprov1 > 50.f) if (Lprov1 < 0.5f) Lprov1 = 0.5f; - if(Chprov1 > 20.f) if (Lprov1 < 0.4f) Lprov1 = 0.4f; - } - Chprov1 *= higherCoef; // decrease the chromaticity value - if (Chprov1 <= 3.0f) - Lprov1 += lowerCoef; - inGamut = false; - } else if (!isHLEnabled && (R>ClipLevel || G>ClipLevel || B>ClipLevel)) { - - // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut -#ifdef _DEBUG - more_rgb=true; -#endif - if (Lprov1 > 99.999f) - Lprov1 = 99.98f; - Chprov1 *= higherCoef; - if (Chprov1 <= 3.0f) - Lprov1 -= lowerCoef; - inGamut = false; - } - } - while (!inGamut); - //end first gamut control - } - - /* - * GamutLchonly correction - * Copyright (c)2012 Jacques Desmis and Jean-Christophe Frisch - * - * This function puts the data (Lab) in the gamut of "working profile": - * it returns the corrected values of the chromaticity and luminance - * - * float HH : hue - * float2 sincosval : sin and cos of HH - * float Lprov1 : input luminance value, sent back corrected - * float Chprov1: input chroma value, sent back corrected - * float R,G,B : red, green and blue value of the corrected color - * double wip : working profile - * bool isHLEnabled : if "highlight reconstruction " is enabled - * float coef : a float number between [0.95 ; 1.0[... the nearest it is from 1.0, the more precise it will be... and the longer too as more iteration will be necessary) - * bool neg and moreRGB : only in DEBUG mode to calculate iterations for negatives values and > 65535 - */ -#ifdef _DEBUG - void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb) -#else - void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef) -#endif - { - const float ClipLevel = 65535.0f; - bool inGamut; -#ifdef _DEBUG - neg=false, more_rgb=false; -#endif - do { - inGamut=true; - - //Lprov1=LL; - float aprov1=Chprov1*sincosval.y; - float bprov1=Chprov1*sincosval.x; - - //conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction - float fy = (0.00862069f *Lprov1 )+ 0.137932f; - float fx = (0.002f * aprov1) + fy; - float fz = fy - (0.005f * bprov1); - - float x_ = 65535.0f * f2xyz(fx)*D50x; - // float y_ = 65535.0f * f2xyz(fy); - float z_ = 65535.0f * f2xyz(fz)*D50z; - float y_=(Lprov1>epskap) ? 65535.0*fy*fy*fy : 65535.0*Lprov1/kappa; - - xyz2rgb(x_,y_,z_,R,G,B,wip); - - // gamut control before saturation to put Lab values in future gamut, but not RGB - if (R<0.0f || G<0.0f || B<0.0f) { -#ifdef _DEBUG - neg=true; -#endif - if (Lprov1 < 0.1f) Lprov1 = 0.1f; - //gamut for L with ultra blue : we can improve the algorithm ... thinner, and other color ??? - if(HH < -0.9f && HH > -1.55f ) {//ultra blue - if(Chprov1 > 160.f) if (Lprov1 < 5.f) Lprov1 = 5.f;//very very very very high chroma - if(Chprov1 > 140.f) if (Lprov1 < 3.5f) Lprov1 = 3.5f; - if(Chprov1 > 120.f) if (Lprov1 < 2.f) Lprov1 = 2.f; - if(Chprov1 > 105.f) if (Lprov1 < 1.f) Lprov1 = 1.f; - if(Chprov1 > 90.f) if (Lprov1 < 0.7f) Lprov1 = 0.7f; - if(Chprov1 > 50.f) if (Lprov1 < 0.5f) Lprov1 = 0.5f; - if(Chprov1 > 20.f) if (Lprov1 < 0.4f) Lprov1 = 0.4f; - } - Chprov1 *= higherCoef; // decrease the chromaticity value - if (Chprov1 <= 3.0f) - Lprov1 += lowerCoef; - inGamut = false; - } else if (!isHLEnabled && (R>ClipLevel || G>ClipLevel || B>ClipLevel)) { - - // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut -#ifdef _DEBUG - more_rgb=true; -#endif - if (Lprov1 > 99.999f) - Lprov1 = 99.98f; - Chprov1 *= higherCoef; - if (Chprov1 <= 3.0f) - Lprov1 -= lowerCoef; - inGamut = false; - } - } - while (!inGamut); - //end first gamut control - } - - -#ifdef _DEBUG - void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb) -#else - void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef) -#endif - { - const float ClipLevel = 65535.0f; - bool inGamut; -#ifdef _DEBUG - neg=false, more_rgb=false; -#endif - do { - inGamut=true; - - //Lprov1=LL; - float aprov1=Chprov1*sincosval.y; - float bprov1=Chprov1*sincosval.x; - - //conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction - float fy = (0.00862069f *Lprov1 )+ 0.137932f; - float fx = (0.002f * aprov1) + fy; - float fz = fy - (0.005f * bprov1); - - float x_ = 65535.0f * f2xyz(fx)*D50x; - // float y_ = 65535.0f * f2xyz(fy); - float z_ = 65535.0f * f2xyz(fz)*D50z; - float y_=(Lprov1>epskap) ? 65535.0*fy*fy*fy : 65535.0*Lprov1/kappa; - - float R,G,B; - xyz2rgb(x_,y_,z_,R,G,B,wip); - - // gamut control before saturation to put Lab values in future gamut, but not RGB - if (R<0.0f || G<0.0f || B<0.0f) { -#ifdef _DEBUG - neg=true; -#endif - if (Lprov1 < 0.01f) - Lprov1 = 0.01f; - Chprov1 *= higherCoef; // decrease the chromaticity value - if (Chprov1 <= 3.0f) - Lprov1 += lowerCoef; - inGamut = false; - } else if (!isHLEnabled && (R>ClipLevel || G>ClipLevel || B>ClipLevel)) { - - // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut -#ifdef _DEBUG - more_rgb=true; -#endif - if (Lprov1 > 99.999f) - Lprov1 = 99.98f; - Chprov1 *= higherCoef; - if (Chprov1 <= 3.0f) - Lprov1 -= lowerCoef; - inGamut = false; - } - } - while (!inGamut); - //end first gamut control - } - /* - * LabGamutMunsell - * Copyright (c) 2012 Jacques Desmis - * - * This function is the overall Munsell's corrections, but only on global statement: I think it's better to use local statement with AllMunsellLch - * not for use in a "for" or "do while" loop - * they are named accordingly : gamutLchonly and AllMunsellLch - * it can be used before and after treatment (saturation, gamma, luminance, ...) - * - * Parameters: - * float *labL : RT Lab L channel data - * float *laba : RT Lab a channel data - * float *labb : RT Lab b channel data - * bool corMunsell : performs Munsell correction - * bool lumaMuns : (used only if corMuns=true) - * true: apply luma + chroma Munsell correction if delta L > 10; - * false: only chroma correction only - * bool gamut : performs gamutLch - * const double wip[3][3]: matrix for working profile - * bool multiThread : parallelize the loop - */ -SSEFUNCTION void Color::LabGamutMunsell(float *labL, float *laba, float *labb, const int N, bool corMunsell, bool lumaMuns, bool isHLEnabled, bool gamut, const double wip[3][3], bool multiThread ) { -#ifdef _DEBUG - MyTime t1e,t2e; - t1e.set(); - int negat=0, moreRGB=0; - MunsellDebugInfo* MunsDebugInfo=NULL; - if (corMunsell) - MunsDebugInfo = new MunsellDebugInfo(); -#endif - float correctlum = 0.f; - float correctionHuechroma = 0.f; -#ifdef __SSE2__ - // precalculate H and C using SSE - float HHBuffer[N]; - float CCBuffer[N]; - __m128 c327d68v = _mm_set1_ps(327.68f); - __m128 av,bv; - int k; - for (k=0; kverbose) { - printf("Color::LabGamutMunsell (correction performed in %d usec):\n", t2e.etime(t1e)); - printf(" Gamut : G1negat=%iiter G165535=%iiter \n",negat,moreRGB); - if (MunsDebugInfo) { - printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); - printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhuelum[0] ,MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); - } - else { - printf(" Munsell correction wasn't requested\n"); - } - } - if (MunsDebugInfo) - delete MunsDebugInfo; -#endif - - } - - /* - * MunsellLch correction - * Copyright (c) 2012 Jacques Desmis - * - * Find the right LUT and calculate the correction - */ - void Color::MunsellLch (float lum, float hue, float chrom, float memChprov, float &correction, int zone, float &lbe, bool &correctL) { - - int x = int(memChprov); - int y = int(chrom); - - //begin PB correction + sky - if(zone==1) { - if(lum > 5.0) { - if(lum <15.0) { - if( (hue >= (_15PB10[x] - 0.035)) && (hue < (_15PB10[x] + 0.052) && x<=45)) {if(y>49) y=49;correction = _15PB10[y] - _15PB10[x] ;lbe=_15PB10[y];correctL=true;} - else if (( hue>=( _3PB10[x] -0.052)) && (hue < (_45PB10[x] + _3PB10[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB10[y] - _3PB10[x]; lbe =_3PB10[y];correctL=true;} - else if (( hue>=(_45PB10[x] + _3PB10[x])/2.0) && (hue < (_45PB10[x] +0.052)) && x <= 85) {if(y>89) y=89;correction = _45PB10[y] - _45PB10[x] ;lbe=_45PB10[y];correctL=true;} - else if (( hue>=(_6PB10[x] -0.052) && (hue < (_6PB10[x] + _75PB10[x])/2.0))) {correction = _6PB10[y] - _6PB10[x] ;lbe=_6PB10[y];correctL=true;} - else if (( hue>=(_6PB10[x] + _75PB10[x])/2.0) && (hue < (_9PB10[x] + _75PB10[x])/2.0)) {correction = _75PB10[y] - _75PB10[x] ;lbe=_75PB10[y];correctL=true;} - else if (( hue>=(_9PB10[x] + _75PB10[x])/2.0) && (hue < (_9PB10[x] + _10PB10[x])/2.0)) {correction = _9PB10[y] - _9PB10[x] ; lbe=_9PB10[y];correctL=true;} - else if (( hue>=(_10PB10[x] + _9PB10[x])/2.0) && (hue < (_1P10[x] + _10PB10[x])/2.0)) {correction = _10PB10[y] - _10PB10[x] ;lbe=_10PB10[y];correctL=true;} - else if (( hue>=(_10PB10[x] + _1P10[x])/2.0) && (hue < (_1P10[x] + _4P10[x])/2.0)) {correction = _1P10[y] - _1P10[x];lbe=_1P10[y];correctL=true;} - else if (( hue>=(_1P10[x] + _4P10[x])/2.0) && (hue < (0.035 + _4P10[x])/2.0)) {correction = _4P10[y] - _4P10[x] ;lbe=_4P10[y];correctL=true;} - } - else if (lum <25.0) { - if( (hue >= (_15PB20[x] - 0.035)) && (hue < (_15PB20[x] + _3PB20[x])/2.0) && x<=85) {if(y>89) y=89;correction = _15PB20[y] - _15PB20[x] ;lbe= _15PB20[y];correctL=true;} - else if (( hue>=(_15PB20[x] + _3PB20[x])/2.0) && (hue < (_45PB20[x] + _3PB20[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB20[y] - _3PB20[x] ;lbe= _3PB20[y];correctL=true;} - else if (( hue>=(_45PB20[x] + _3PB20[x])/2.0) && (hue < ( _45PB20[x] + 0.052)) && x <= 85) {if(y>89) y=89;correction = _45PB20[y] - _45PB20[x] ;lbe=_45PB20[y];correctL=true;} - else if (( hue>=(_45PB20[x] + 0.052)) && (hue < (_6PB20[x] + _75PB20[x])/2.0)) {correction = _6PB20[y] - _6PB20[x];lbe=_6PB20[y];correctL=true;} - else if (( hue>=(_6PB20[x] + _75PB20[x])/2.0) && (hue < (_9PB20[x] + _75PB20[x])/2.0)) {correction = _75PB20[y] - _75PB20[x] ;lbe=_75PB20[y];correctL=true;} - else if (( hue>=(_9PB20[x] + _75PB20[x])/2.0) && (hue < (_9PB20[x] + _10PB20[x])/2.0)) {correction = _9PB20[y] - _9PB20[x] ;lbe= _9PB20[y];correctL=true; } - else if (( hue>=(_10PB20[x] + _9PB20[x])/2.0) && (hue < (_1P20[x] + _10PB20[x])/2.0)) {correction = _10PB20[y] - _10PB20[x] ;lbe= _10PB20[y];correctL=true;} - else if (( hue>=(_10PB20[x] + _1P20[x])/2.0) && (hue < (_1P20[x] + _4P20[x])/2.0)) {correction = _1P20[y] - _1P20[x] ; lbe=_1P20[y];correctL=true;} - else if (( hue>=(_1P20[x] + _4P20[x])/2.0) && (hue < (0.035 + _4P20[x])/2.0)) {correction = _4P20[y] - _4P20[x] ; lbe=_4P20[y];correctL=true;} - } - else if (lum <35.0) { - if( (hue >= (_15PB30[x] - 0.035)) && (hue < (_15PB30[x] + _3PB30[x])/2.0) && x<=85 ) {if(y>89) y=89;correction = _15PB30[y] - _15PB30[x] ;lbe=_15PB30[y];correctL=true;} - else if (( hue>=(_15PB30[x] + _3PB30[x])/2.0) && (hue < (_45PB30[x] + _3PB30[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB30[y] - _3PB30[x] ;lbe=_3PB30[y];correctL=true;} - else if (( hue>=(_45PB30[x] + _3PB30[x])/2.0) && (hue < (_45PB30[x]+0.052)) && x <= 85) {if(y>89) y=89;correction = _45PB30[y] - _45PB30[x] ;lbe= _45PB30[y];correctL=true;} - else if (( hue>=( _45PB30[x]+ 0.052)) && (hue < (_6PB30[x] + _75PB30[x])/2.0)) {correction = _6PB30[y] - _6PB30[x] ; lbe=_6PB30[y];correctL=true;} - else if (( hue>=(_6PB30[x] + _75PB30[x])/2.0) && (hue < (_9PB30[x] + _75PB30[x])/2.0)) {correction = _75PB30[y] - _75PB30[x] ;lbe= _75PB30[y] ;correctL=true;} - else if (( hue>=(_9PB30[x] + _75PB30[x])/2.0) && (hue < (_9PB30[x] + _10PB30[x])/2.0)) {correction = _9PB30[y] - _9PB30[x] ;lbe=_9PB30[y]; correctL=true;} - else if (( hue>=(_10PB30[x] + _9PB30[x])/2.0) && (hue < (_1P30[x] + _10PB30[x])/2.0)) {correction = _10PB30[y] - _10PB30[x] ;lbe=_10PB30[y];correctL=true;} - else if (( hue>=(_10PB30[x] + _1P30[x])/2.0) && (hue < (_1P30[x] + _4P30[x])/2.0)) {correction = _1P30[y] - _1P30[x] ;lbe=_1P30[y];correctL=true; } - else if (( hue>=(_1P30[x] + _4P30[x])/2.0) && (hue < (0.035 + _4P30[x])/2.0)) {correction = _4P30[y] - _4P30[x] ;lbe=_4P30[y];correctL=true;} - } - else if (lum <45.0) { - if( (hue <= (_05PB40[x] + _15PB40[x])/2.0) && (hue > (_05PB40[x] + _10B40[x])/2.0) && x<75 ) {if(y>75) y=75; correction = _05PB40[y] - _05PB40[x] ;lbe=_05PB40[y];correctL=true;} - else if( (hue <= (_05PB40[x] + _10B40[x])/2.0) && (hue >(_10B40[x] + _9B40[x])/2.0) && x<70 ) {if(y>70) y=70;correction = _10B40[y] - _10B40[x] ;lbe=_10B40[y];correctL=true;} - else if( (hue <= (_10B40[x] + _9B40[x])/2.0) && (hue >(_9B40[x] + _7B40[x])/2.0) && x<70 ) {if(y>70) y=70;correction = _9B40[y] - _9B40[x] ;lbe=_9B40[y];correctL=true;} - else if( (hue <= (_9B40[x] + _7B40[x])/2.0) && (hue >(_5B40[x] + _7B40[x])/2.0) && x<70 ) {if(y>70) y=70;correction = _7B40[y] - _7B40[x] ;lbe= _7B40[y];correctL=true;} - else if (( hue<=(_5B40[x] + _7B40[x])/2.0) && (hue > (_5B40[x]-0.035)) && x < 70) {if(y>70) y=70; correction = _5B40[y] - _5B40[x] ;lbe= _5B40[y];correctL=true;} // - - else if( (hue >= (_15PB40[x] - 0.035)) && (hue < (_15PB40[x] + _3PB40[x])/2.0) && x<=85 ) {if(y>89) y=89;correction = _15PB40[y] - _15PB40[x] ; lbe= _15PB40[y];correctL=true;} - else if (( hue>=(_15PB40[x] + _3PB40[x])/2.0) && (hue < (_45PB40[x] + _3PB40[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB40[y] - _3PB40[x] ;lbe=_3PB40[y];correctL=true;} - else if (( hue>=(_45PB40[x] + _3PB40[x])/2.0) && (hue < (_45PB40[x]+0.052)) && x <= 85) {if(y>89) y=89;correction = _45PB40[y] - _45PB40[x] ;lbe=_45PB40[y] ;correctL=true;} - else if (( hue>=(_45PB40[x]+0.052)) && (hue < (_6PB40[x] + _75PB40[x])/2.0)) {correction = _6PB40[y] - _6PB40[x] ;lbe=_6PB40[y];correctL=true; } - else if (( hue>=(_6PB40[x] + _75PB40[x])/2.0) && (hue < (_9PB40[x] + _75PB40[x])/2.0)) {correction = _75PB40[y] - _75PB40[x] ; lbe=_75PB40[y];correctL=true;} - else if (( hue>=(_9PB40[x] + _75PB40[x])/2.0) && (hue < (_9PB40[x] + _10PB40[x])/2.0)) {correction = _9PB40[y] - _9PB40[x] ;lbe= _9PB40[y]; correctL=true;} - else if (( hue>=(_10PB40[x] + _9PB40[x])/2.0) && (hue < (_1P40[x] + _10PB40[x])/2.0)) {correction = _10PB40[y] - _10PB40[x] ;lbe=_10PB40[y];correctL=true;} - else if (( hue>=(_10PB40[x] + _1P40[x])/2.0) && (hue < (_1P40[x] + _4P40[x])/2.0)) {correction = _1P40[y] - _1P40[x] ;lbe=_1P40[y];correctL=true;} - else if (( hue>=(_1P40[x] + _4P40[x])/2.0) && (hue < (0.035 + _4P40[x])/2.0)) {correction = _4P40[y] - _4P40[x] ;lbe= _4P40[y];correctL=true;} - } - else if (lum <55.0) { - if( (hue <= (_05PB50[x] + _15PB50[x])/2.0) && (hue > (_05PB50[x] + _10B50[x])/2.0) && x<79 ) {if(y>79) y=79; correction = _05PB50[y] - _05PB50[x] ;lbe= _05PB50[y];correctL=true;} - else if( (hue <= (_05PB50[x] + _10B50[x])/2.0) && (hue >(_10B50[x] + _9B50[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _10B50[y] - _10B50[x] ;lbe=_10B50[y];correctL=true;} - else if( (hue <= (_10B50[x] + _9B50[x])/2.0) && (hue >(_9B50[x] + _7B50[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _9B50[y] - _9B50[x] ;lbe=_9B50[y];correctL=true;} - else if( (hue <= (_9B50[x] + _7B50[x])/2.0) && (hue >(_5B50[x] + _7B50[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _7B50[y] - _7B50[x] ;lbe=_7B50[y];correctL=true;} - else if (( hue<=(_5B50[x] + _7B50[x])/2.0) && (hue > (_5B50[x]-0.035)) && x < 79) {if(y>79) y=79; correction = _5B50[y] - _5B50[x] ;lbe=_5B50[y];correctL=true; } // - - else if( (hue >= (_15PB50[x] - 0.035)) && (hue < (_15PB50[x] + _3PB50[x])/2.0) && x<=85 ) {if(y>89) y=89;correction = _15PB50[y] - _15PB50[x] ; lbe= _15PB50[y];correctL=true;} - else if (( hue>=(_15PB50[x] + _3PB50[x])/2.0) && (hue < (_45PB50[x] + _3PB50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB50[y] - _3PB50[x] ;lbe=_3PB50[y];correctL=true;} - else if (( hue>=(_45PB50[x] + _3PB50[x])/2.0) && (hue < (_6PB50[x] + _45PB50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _45PB50[y] - _45PB50[x] ;lbe=_45PB50[y];correctL=true; } - else if (( hue>=(_6PB50[x] + _45PB50[x])/2.0) && (hue < (_6PB50[x] + _75PB50[x])/2.0) && x <=85) {if(y>89) y=89;correction = _6PB50[y] - _6PB50[x] ;lbe=_6PB50[y];correctL=true;} - else if (( hue>=(_6PB50[x] + _75PB50[x])/2.0) && (hue < (_9PB50[x] + _75PB50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _75PB50[y] - _75PB50[x] ;lbe=_75PB50[y];correctL=true;} - else if (( hue>=(_9PB50[x] + _75PB50[x])/2.0) && (hue < (_9PB50[x] + _10PB50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _9PB50[y] - _9PB50[x] ;lbe=_9PB50[y];correctL=true;} - else if (( hue>=(_10PB50[x] + _9PB50[x])/2.0) && (hue < (_1P50[x] + _10PB50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _10PB50[y] - _10PB50[x] ;lbe=_10PB50[y];correctL=true;} - else if (( hue>=(_10PB50[x] + _1P50[x])/2.0) && (hue < (_1P50[x] + _4P50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _1P50[y] - _1P50[x] ;lbe=_1P50[y];correctL=true; } - else if (( hue>=(_1P50[x] + _4P50[x])/2.0) && (hue < (0.035 + _4P50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _4P50[y] - _4P50[x] ;lbe=_4P50[y];correctL=true;} - } - else if (lum <65.0) { - if( (hue <= (_05PB60[x] + _15PB60[x])/2.0) && (hue > (_05PB60[x] + _10B60[x])/2.0) && x<79 ) {if(y>79) y=79; correction = _05PB60[y] - _05PB60[x] ;lbe=_05PB60[y];correctL=true;} - else if( (hue <= (_05PB60[x] + _10B60[x])/2.0) && (hue >(_10B60[x] + _9B60[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _10B60[y] - _10B60[x] ;lbe= _10B60[y];correctL=true;} - else if( (hue <= (_10B60[x] + _9B60[x])/2.0) && (hue >(_9B60[x] + _7B60[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _9B60[y] - _9B60[x] ;lbe=_9B60[y];correctL=true;} - else if( (hue <= (_9B60[x] + _7B60[x])/2.0) && (hue >(_5B60[x] + _7B60[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _7B60[y] - _7B60[x] ;lbe= _7B60[y];correctL=true;} - else if (( hue<=(_5B60[x] + _7B60[x])/2.0) && (hue > (_5B60[x]-0.035)) && x < 79) {if(y>79) y=79; correction = _5B60[y] - _5B60[x] ;lbe= _5B60[y];correctL=true;} // - - else if( (hue >= (_15PB60[x] - 0.035)) && (hue < (_15PB60[x] + _3PB60[x])/2.0) && x<=85 ) {if(y>89) y=89;correction = _15PB60[y] - _15PB60[x] ;lbe=_15PB60[y];correctL=true; } - else if (( hue>=(_15PB60[x] + _3PB60[x])/2.0) && (hue < (_45PB60[x] + _3PB60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB60[y] - _3PB60[x] ;lbe=_3PB60[y];correctL=true;} - else if (( hue>=(_45PB60[x] + _3PB60[x])/2.0) && (hue < (_6PB60[x] + _45PB60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _45PB60[y] - _45PB60[x] ;lbe=_45PB60[y];correctL=true;} - else if (( hue>=(_6PB60[x] + _45PB60[x])/2.0) && (hue < (_6PB60[x] + _75PB60[x])/2.0) && x <=85) {if(y>89) y=89;correction = _6PB60[y] - _6PB60[x] ;lbe= _6PB60[y];correctL=true;} - else if (( hue>=(_6PB60[x] + _75PB60[x])/2.0) && (hue < (_9PB60[x] + _75PB60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _75PB60[y] - _75PB60[x] ;lbe= _75PB60[y];correctL=true;} - else if (( hue>=(_9PB60[x] + _75PB60[x])/2.0) && (hue < (_9PB60[x] + _10PB60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _9PB60[y] - _9PB60[x] ;lbe= _9PB60[y];correctL=true;} - else if (( hue>=(_10PB60[x] + _9PB60[x])/2.0) && (hue < (_1P60[x] + _10PB60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _10PB60[y] - _10PB60[x] ;lbe=_10PB60[y]; correctL=true;} - else if (( hue>=(_10PB60[x] + _1P60[x])/2.0) && (hue < (_1P60[x] + _4P60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _1P60[y] - _1P60[x] ; lbe= _1P60[y];correctL=true;} - else if (( hue>=(_1P60[x] + _4P60[x])/2.0) && (hue < (0.035 + _4P60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _4P60[y] - _4P60[x] ;lbe=_4P60[y];correctL=true; } - } - else if (lum < 75.0) { - if( (hue <= (_05PB70[x] + _15PB70[x])/2.0) && (hue > (_05PB70[x] + _10B70[x])/2.0) && x<50 ) {if(y>49) y=49; correction = _05PB70[y] - _05PB70[x] ;lbe=_05PB70[y];correctL=true;} - else if( (hue <= (_05PB70[x] + _10B70[x])/2.0) && (hue >(_10B70[x] + _9B70[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _10B70[y] - _10B70[x] ;lbe=_10B70[y];correctL=true;} - else if( (hue <= (_10B70[x] + _9B70[x])/2.0) && (hue >(_9B70[x] + _7B70[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _9B70[y] - _9B70[x] ;lbe= _9B70[y];correctL=true;} - else if( (hue <= (_9B70[x] + _7B70[x])/2.0) && (hue >(_5B70[x] + _7B70[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _7B70[y] - _7B70[x] ;lbe=_7B70[y];correctL=true;} - else if (( hue<=(_5B70[x] + _7B70[x])/2.0) && (hue > (_5B70[x]-0.035)) && x < 50) {if(y>49) y=49; correction = _5B70[y] - _5B70[x] ;lbe= _5B70[y];correctL=true;} // - - else if( (hue >= (_15PB70[x] - 0.035)) && (hue < (_15PB70[x] + _3PB70[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _15PB70[y] - _15PB70[x] ;lbe=_15PB70[y];correctL=true; } - else if (( hue>=(_45PB70[x] + _3PB70[x])/2.0) && (hue < (_6PB70[x] + _45PB70[x])/2.0) && x < 50) {if(y>49) y=49;correction = _45PB70[y] - _45PB70[x] ;lbe=_45PB70[y];correctL=true;} - else if (( hue>=(_6PB70[x] + _45PB70[x])/2.0) && (hue < (_6PB70[x] + _75PB70[x])/2.0) && x <50) {if(y>49) y=49;correction = _6PB70[y] - _6PB70[x] ;lbe=_6PB70[y];correctL=true;} - else if (( hue>=(_6PB70[x] + _75PB70[x])/2.0) && (hue < (_9PB70[x] + _75PB70[x])/2.0) && x <50) {if(y>49) y=49;correction = _75PB70[y] - _75PB70[x] ;lbe=_75PB70[y];correctL=true; } - else if (( hue>=(_9PB70[x] + _75PB70[x])/2.0) && (hue < (_9PB70[x] + 0.035)) && x <50) {if(y>49) y=49;correction = _9PB70[y] - _9PB70[x] ;lbe=_9PB70[y];correctL=true;} - } - else if (lum < 85.0) { - if( (hue <= (_05PB80[x] + _15PB80[x])/2.0) && (hue > (_05PB80[x] + _10B80[x])/2.0) && x<40 ) {if(y>39) y=39; correction = _05PB80[y] - _05PB80[x] ;lbe=_05PB80[y] ;correctL=true;} - else if( (hue <= (_05PB80[x] + _10B80[x])/2.0) && (hue >(_10B80[x] + _9B80[x])/2.0) && x<40 ) {if(y>39) y=39;correction = _10B80[y] - _10B80[x] ;lbe=_10B80[y];correctL=true;} - else if( (hue <= (_10B80[x] + _9B80[x])/2.0) && (hue >(_9B80[x] + _7B80[x])/2.0) && x<40 ) {if(y>39) y=39;correction = _9B80[y] - _9B80[x] ;lbe= _9B80[y];correctL=true;} - else if( (hue <= (_9B80[x] + _7B80[x])/2.0) && (hue >(_5B80[x] + _7B80[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _7B80[y] - _7B80[x] ;lbe=_7B80[y];correctL=true;} - else if (( hue<=(_5B80[x] + _7B80[x])/2.0) && (hue > (_5B80[x]-0.035)) && x < 50) {if(y>49) y=49; correction = _5B80[y] - _5B80[x] ; lbe=_5B80[y];correctL=true;} // - - else if( (hue >= (_15PB80[x] - 0.035)) && (hue < (_15PB80[x] + _3PB80[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _15PB80[y] - _15PB80[x] ; lbe=_15PB80[y];correctL=true;} - else if (( hue>=(_45PB80[x] + _3PB80[x])/2.0) && (hue < (_6PB80[x] + _45PB80[x])/2.0) && x < 50) {if(y>49) y=49;correction = _45PB80[y] - _45PB80[x] ;lbe= _45PB80[y];correctL=true;} - else if (( hue>=(_6PB80[x] + _45PB80[x])/2.0) && (hue < (_6PB80[x] + _75PB80[x])/2.0) && x <50) {if(y>49) y=49;correction = _6PB80[y] - _6PB80[x] ;lbe=_6PB80[y];correctL=true;} - else if (( hue>=(_6PB80[x] + _75PB80[x])/2.0) && (hue < (_9PB80[x] + _75PB80[x])/2.0) && x <50) {if(y>49) y=49;correction = _75PB80[y] - _75PB80[x] ;lbe=_75PB80[y];correctL=true; } - else if (( hue>=(_9PB80[x] + _75PB80[x])/2.0) && (hue < (_9PB80[x] + 0.035)) && x <50) {if(y>49) y=49;correction = _9PB80[y] - _9PB80[x] ;lbe=_9PB80[y]; correctL=true;} - } - } - } - // end PB correction - - //red yellow correction - else if(zone==2) { - if(lum > 15.0) { - if(lum < 25.0) { - if( (hue <= (_10YR20[x] + 0.035)) && (hue > (_10YR20[x] + _85YR20[x])/2.0) && x<=45) {if(y>49) y=49;correction = _10YR20[y] - _10YR20[x] ;lbe=_10YR20[y];correctL=true;} - else if (( hue<=(_85YR20[x] + _10YR20[x])/2.0) && (hue > (_85YR20[x] + 0.035) && x <= 45)) {if(y>49) y=49;correction = _85YR20[y] - _85YR20[x] ;lbe= _85YR20[y];correctL=true;} - } - else if (lum <35.0) { - if( (hue <= (_10YR30[x] + 0.035)) && (hue > (_10YR30[x] + _85YR30[x])/2.0) && x < 85) {if(y>89) y=89;correction = _10YR30[y] - _10YR30[x] ;lbe=_10YR30[y];correctL=true;} - else if( (hue <= (_10YR30[x] + _85YR30[x])/2.0) && (hue >(_85YR30[x] + _7YR30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _85YR30[y] - _85YR30[x] ;lbe= _85YR30[y];correctL=true;} - else if (( hue<=(_85YR30[x] + _7YR30[x])/2.0) && (hue > (_7YR30[x] + _55YR30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _7YR30[y] - _7YR30[x] ;lbe=_7YR30[y];correctL=true;} - else if (( hue<=(_7YR30[x] + _55YR30[x])/2.0) && (hue > (_55YR30[x] + _4YR30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _55YR30[y] - _55YR30[x] ;lbe=_55YR30[y];correctL=true; } - else if (( hue<=(_55YR30[x] + _4YR30[x])/2.0) && (hue > (_4YR30[x] + _25YR30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _4YR30[y] - _4YR30[x] ;lbe= _4YR30[y];correctL=true;} - else if (( hue<=(_4YR30[x] + _25YR30[x])/2.0) && (hue > (_25YR30[x] + _10R30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _25YR30[y] - _25YR30[x] ;lbe=_25YR30[y];correctL=true;} - else if (( hue<=(_25YR30[x] + _10R30[x])/2.0) && (hue > (_10R30[x] + _9R30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10R30[y] - _10R30[x] ; lbe=_10R30[y];correctL=true;} - else if (( hue<=(_10R30[x] + _9R30[x])/2.0) && (hue > (_9R30[x] + _7R30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _9R30[y] - _9R30[x] ;lbe=_9R30[y];correctL=true;} - else if (( hue<=(_9R30[x] + _7R30[x])/2.0) && (hue > (_7R30[x] -0.035))&& x < 85) {if(y>89) y=89;correction = _7R30[y] - _7R30[x] ; lbe=_7R30[y] ;correctL=true;} - } - else if (lum <45.0) { - if( (hue <= (_10YR40[x] + 0.035)) && (hue > (_10YR40[x] + _85YR40[x])/2.0)&& x<85) {if(y>89) y=89;correction = _10YR40[y] - _10YR40[x] ;lbe=_10YR40[y];correctL=true;} - else if( (hue <= (_10YR40[x] + _85YR40[x])/2.0) && (hue >(_85YR40[x] + _7YR40[x])/2.0)&& x < 85 ) {if(y>89) y=89;correction = _85YR40[y] - _85YR40[x] ;lbe= _85YR40[y];correctL=true;} - else if (( hue<=(_85YR40[x] + _7YR40[x])/2.0) && (hue > (_7YR40[x] + _55YR40[x])/2.0) && x < 85) {if(y>89) y=89;correction = _7YR40[y] - _7YR40[x] ;lbe= _7YR40[y];correctL=true;} - else if (( hue<=(_7YR40[x] + _55YR40[x])/2.0) && (hue > (_55YR40[x] + _4YR40[x])/2.0)&& x < 85 ) {if(y>89) y=89;correction = _55YR40[y] - _55YR40[x] ;lbe=_55YR40[y];correctL=true; } - else if (( hue<=(_55YR40[x] + _4YR40[x])/2.0) && (hue > (_4YR40[x] + _25YR40[x])/2.0)&& x < 85 ) {if(y>89) y=89;correction = _4YR40[y] - _4YR40[x] ;lbe=_4YR40[y]; correctL=true;} - else if (( hue<=(_4YR40[x] + _25YR40[x])/2.0) && (hue > (_25YR40[x] + _10R40[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _25YR40[y] - _25YR40[x] ;lbe=_25YR40[y] ;correctL=true;} - else if (( hue<=(_25YR40[x] + _10R40[x])/2.0) && (hue > (_10R40[x] + _9R40[x])/2.0) && x < 85) {if(y>89) y=89;correction = _10R40[y] - _10R40[x] ; lbe=_10R40[y];correctL=true;} - else if (( hue<=(_10R40[x] + _9R40[x])/2.0) && (hue > (_9R40[x] + _7R40[x])/2.0)&& x < 85 ) {if(y>89) y=89;correction = _9R40[y] - _9R40[x] ;lbe=_9R40[y];correctL=true;} - else if (( hue<=(_9R40[x] + _7R40[x])/2.0) && (hue > (_7R40[x] -0.035))&& x < 85 ) {if(y>89) y=89;correction = _7R40[y] - _7R40[x] ; lbe=_7R40[y];correctL=true;} - } - else if (lum <55.0) { - if( (hue <= (_10YR50[x] + 0.035)) && (hue > (_10YR50[x] + _85YR50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10YR50[y] - _10YR50[x] ;lbe=_10YR50[y];correctL=true;} - else if( (hue <= (_10YR50[x] + _85YR50[x])/2.0) && (hue >(_85YR50[x] + _7YR50[x])/2.0)&& x < 85 ) {if(y>89) y=89;correction = _85YR50[y] - _85YR50[x] ;lbe=_85YR50[y];correctL=true;} - else if (( hue<=(_85YR50[x] + _7YR50[x])/2.0) && (hue > (_7YR50[x] + _55YR50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _7YR50[y] - _7YR50[x] ;lbe=_7YR50[y];correctL=true;} - else if (( hue<=(_7YR50[x] + _55YR50[x])/2.0) && (hue > (_55YR50[x] + _4YR50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _55YR50[y] - _55YR50[x] ; lbe=_55YR50[y];correctL=true;} - else if (( hue<=(_55YR50[x] + _4YR50[x])/2.0) && (hue > (_4YR50[x] + _25YR50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _4YR50[y] - _4YR50[x] ;lbe=_4YR50[y]; correctL=true;} - else if (( hue<=(_4YR50[x] + _25YR50[x])/2.0) && (hue > (_25YR50[x] + _10R50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _25YR50[y] - _25YR50[x] ;lbe=_25YR50[y];correctL=true;} - else if (( hue<=(_25YR50[x] + _10R50[x])/2.0) && (hue > (_10R50[x] + _9R50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10R50[y] - _10R50[x] ;lbe= _10R50[y]; correctL=true;} - else if (( hue<=(_10R50[x] + _9R50[x])/2.0) && (hue > (_9R50[x] + _7R50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _9R50[y] - _9R50[x] ;lbe=_9R50[y];correctL=true;} - else if (( hue<=(_9R50[x] + _7R50[x])/2.0) && (hue > (_7R50[x] -0.035))&& x < 85) {if(y>89) y=89;correction = _7R50[y] - _7R50[x] ; lbe=_7R50[y];correctL=true;} - } - else if (lum <65.0) { - if( (hue <= (_10YR60[x] + 0.035)) && (hue > (_10YR60[x] + _85YR60[x])/2.0)) {;correction = _10YR60[y] - _10YR60[x] ;lbe= _10YR60[y];correctL=true;} - else if( (hue <= (_10YR60[x] + _85YR60[x])/2.0) && (hue >(_85YR60[x] + _7YR60[x])/2.0) ) {;correction = _85YR60[y] - _85YR60[x] ;lbe= _85YR60[y];correctL=true;} - else if (( hue<=(_85YR60[x] + _7YR60[x])/2.0) && (hue > (_7YR60[x] + _55YR60[x])/2.0)) {correction = _7YR60[y] - _7YR60[x] ;lbe=_7YR60[y];correctL=true;} - else if (( hue<=(_7YR60[x] + _55YR60[x])/2.0) && (hue > (_55YR60[x] + _4YR60[x])/2.0)) {correction = _55YR60[y] - _55YR60[x] ;lbe= _55YR60[y];correctL=true;} - else if (( hue<=(_55YR60[x] + _4YR60[x])/2.0) && (hue > (_4YR60[x] + _25YR60[x])/2.0)) {correction = _4YR60[y] - _4YR60[x] ;lbe=_4YR60[y]; correctL=true;} - else if (( hue<=(_4YR60[x] + _25YR60[x])/2.0) && (hue > (_25YR60[x] + _10R60[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _25YR60[y] - _25YR60[x] ;lbe=_25YR60[y];correctL=true;} - else if (( hue<=(_25YR60[x] + _10R60[x])/2.0) && (hue > (_10R60[x] + _9R60[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10R60[y] - _10R60[x] ;lbe= _10R60[y];correctL=true; } - else if (( hue<=(_10R60[x] + _9R60[x])/2.0) && (hue > (_9R60[x] + _7R60[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _9R60[y] - _9R60[x] ;lbe=_9R60[y];correctL=true;} - else if (( hue<=(_9R60[x] + _7R60[x])/2.0) && (hue > (_7R60[x] -0.035))&& x < 85) {if(y>89) y=89;correction = _7R60[y] - _7R60[x] ;lbe=_7R60[y]; correctL=true;} - } - else if (lum <75.0) { - if( (hue <= (_10YR70[x] + 0.035)) && (hue > (_10YR70[x] + _85YR70[x])/2.0)) {correction = _10YR70[y] - _10YR70[x] ;lbe= _10YR70[y];correctL=true;} - else if( (hue <= (_10YR70[x] + _85YR70[x])/2.0) && (hue >(_85YR70[x] + _7YR70[x])/2.0)) {correction = _85YR70[y] - _85YR70[x] ;lbe=_85YR70[y];correctL=true;} - if (( hue<=(_85YR70[x] + _7YR70[x])/2.0) && (hue > (_7YR70[x] + _55YR70[x])/2.0)) {correction = _7YR70[y] - _7YR70[x] ;lbe=_7YR70[y];correctL=true;} - else if (( hue<=(_7YR70[x] + _55YR70[x])/2.0) && (hue > (_55YR70[x] + _4YR70[x])/2.0)) {correction = _55YR70[y] - _55YR70[x] ;lbe=_55YR70[y];correctL=true; } - else if (( hue<=(_55YR70[x] + _4YR70[x])/2.0) && (hue > (_4YR70[x] + _25YR70[x])/2.0)) {correction = _4YR70[y] - _4YR70[x] ;lbe=_4YR70[y];correctL=true; } - else if (( hue<=(_4YR70[x] + _25YR70[x])/2.0) && (hue > (_25YR70[x] + _10R70[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _25YR70[y] - _25YR70[x] ;lbe= _25YR70[y];correctL=true;} - else if (( hue<=(_25YR70[x] + _10R70[x])/2.0) && (hue > (_10R70[x] + _9R70[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10R70[y] - _10R70[x] ;lbe= _10R70[y];correctL=true;} - else if (( hue<=(_10R70[x] + _9R70[x])/2.0) && (hue > (_9R70[x] + _7R70[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _9R70[y] - _9R70[x] ;lbe= _9R70[y] ;correctL=true;} - else if (( hue<=(_9R70[x] + _7R70[x])/2.0) && (hue > (_7R70[x] -0.035))&& x < 85) {if(y>89) y=89;correction = _7R70[y] - _7R70[x] ;lbe=_7R70[y];correctL=true; } - } - else if (lum <85.0) { - if( (hue <= (_10YR80[x] + 0.035)) && (hue > (_10YR80[x] + _85YR80[x])/2.0)) {correction = _10YR80[y] - _10YR80[x] ;lbe=_10YR80[y];correctL=true;} - else if( (hue <= (_10YR80[x] + _85YR80[x])/2.0) && (hue >(_85YR80[x] + _7YR80[x])/2.0)) {correction = _85YR80[y] - _85YR80[x] ;lbe= _85YR80[y];} - else if (( hue<=(_85YR80[x] + _7YR80[x])/2.0) && (hue > (_7YR80[x] + _55YR80[x])/2.0) && x<85) {if(y>89) y=89;correction = _7YR80[y] - _7YR80[x] ;lbe=_7YR80[y];correctL=true;} - else if (( hue<=(_7YR80[x] + _55YR80[x])/2.0) && (hue > (_55YR80[x] + _4YR80[x])/2.0) && x <45) {correction = _55YR80[y] - _55YR80[x] ;lbe=_55YR80[y];correctL=true; } - else if (( hue<=(_55YR80[x] + _4YR80[x])/2.0) && (hue > (_4YR80[x] - 0.035) && x<45)) {if(y>49) y=49;correction = _4YR80[y] - _4YR80[x] ; lbe=_4YR80[y] ;correctL=true;} - } - else if (lum <95.0) { - if( (hue <= (_10YR90[x] + 0.035)) && (hue > (_10YR90[x] -0.035) && x<85)) {if(y>89) y=89;correction = _10YR90[y] - _10YR90[x] ;lbe= _10YR90[y];correctL=true;} - else if ( hue<=(_85YR90[x] + 0.035) && hue > (_85YR90[x] -0.035) && x<85) {if(y>89) y=89;correction = _85YR90[y] - _85YR90[x] ;lbe=_85YR90[y];correctL=true;} - else if (( hue<=(_55YR90[x] + 0.035) && (hue > (_55YR90[x] - 0.035) && x<45))) {if(y>49) y=49;correction = _55YR90[y] - _55YR90[x] ;lbe= _55YR90[y];correctL=true; } - } - } - } - //end red yellow - - //Green yellow correction - else if(zone==3) { - if (lum >= 25.0) { - if (lum <35.0) { - if( (hue <= (_7G30[x] + 0.035)) && (hue > (_7G30[x] + _5G30[x])/2.0) ) {correction = _7G30[y] - _7G30[x] ;lbe=_7G30[y];correctL=true;} - else if( (hue <= (_7G30[x] + _5G30[x])/2.0) && (hue >(_5G30[x] + _25G30[x])/2.0)) {correction = _5G30[y] - _5G30[x] ;lbe= _5G30[y];correctL=true;} - else if (( hue<=(_25G30[x] + _5G30[x])/2.0) && (hue > (_25G30[x] + _1G30[x])/2.0)) {correction = _25G30[y] - _25G30[x] ;lbe=_25G30[y];correctL=true;} - else if (( hue<=(_1G30[x] + _25G30[x])/2.0) && (hue > (_1G30[x] + _10GY30[x])/2.0)) {correction = _1G30[y] - _1G30[x] ;lbe= _1G30[y];correctL=true;} - else if (( hue<=(_1G30[x] + _10GY30[x])/2.0) && (hue > (_10GY30[x] + _75GY30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10GY30[y] - _10GY30[x] ;lbe= _10GY30[y];correctL=true;} - else if (( hue<=(_10GY30[x] + _75GY30[x])/2.0) && (hue > (_75GY30[x] + _5GY30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _75GY30[y] - _75GY30[x] ;lbe=_75GY30[y];correctL=true;} - else if (( hue<=(_5GY30[x] + _75GY30[x])/2.0) && (hue > (_5GY30[x] -0.035))&& x < 85) {if(y>89) y=89;correction = _5GY30[y] - _5GY30[x] ;lbe= _5GY30[y] ;correctL=true; } - } - else if (lum <45.0) { - if( (hue <= (_7G40[x] + 0.035)) && (hue > (_7G40[x] + _5G40[x])/2.0) ) {correction = _7G40[y] - _7G40[x] ;lbe= _7G40[y];correctL=true;} - else if( (hue <= (_7G40[x] + _5G40[x])/2.0) && (hue >(_5G40[x] + _25G40[x])/2.0)) {correction = _5G40[y] - _5G40[x] ;lbe=_5G40[y];correctL=true;} - else if (( hue<=(_25G40[x] + _5G40[x])/2.0) && (hue > (_25G40[x] + _1G40[x])/2.0)) {correction = _25G40[y] - _25G40[x] ;lbe=_25G40[y];correctL=true;} - else if (( hue<=(_1G40[x] + _25G40[x])/2.0) && (hue > (_1G40[x] + _10GY40[x])/2.0)) {correction = _1G40[y] - _1G40[x] ;lbe=_1G40[y];correctL=true; } - else if (( hue<=(_1G40[x] + _10GY40[x])/2.0) && (hue > (_10GY40[x] + _75GY40[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10GY40[y] - _10GY40[x] ;lbe=_10GY40[y];correctL=true; } - else if (( hue<=(_10GY40[x] + _75GY40[x])/2.0) && (hue > (_75GY40[x] + _5GY40[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _75GY40[y] - _75GY40[x] ;lbe=_75GY40[y];correctL=true;} - else if (( hue<=(_5GY40[x] + _75GY40[x])/2.0) && (hue > (_5GY40[x]-0.035)) && x < 85) {if(y>89) y=89; correction = _5GY40[y] - _5GY40[x] ;lbe=_5GY40[y];correctL=true; } // - } - else if (lum <55.0) { - if( (hue <= (_7G50[x] + 0.035)) && (hue > (_7G50[x] + _5G50[x])/2.0) ) {correction = _7G50[y] - _7G50[x] ;lbe=_7G50[y];correctL=true;} - else if( (hue <= (_7G50[x] + _5G50[x])/2.0) && (hue >(_5G50[x] + _25G50[x])/2.0)) {correction = _5G50[y] - _5G50[x] ;lbe=_5G50[y];correctL=true;} - else if (( hue<=(_25G50[x] + _5G50[x])/2.0) && (hue > (_25G50[x] + _1G50[x])/2.0)) {correction = _25G50[y] - _25G50[x] ;lbe= _25G50[y];correctL=true;} - else if (( hue<=(_1G50[x] + _25G50[x])/2.0) && (hue > (_1G50[x] + _10GY50[x])/2.0)) {correction = _1G50[y] - _1G50[x] ; lbe=_1G50[y];correctL=true;} - else if (( hue<=(_1G50[x] + _10GY50[x])/2.0) && (hue > (_10GY50[x] + _75GY50[x])/2.0)) {correction = _10GY50[y] - _10GY50[x] ;lbe= _10GY50[y];correctL=true;} - else if (( hue<=(_10GY50[x] + _75GY50[x])/2.0) && (hue > (_75GY50[x] + _5GY50[x])/2.0)) {correction = _75GY50[y] - _75GY50[x] ;lbe=_75GY50[y];correctL=true;} - else if (( hue<=(_5GY50[x] + _75GY50[x])/2.0) && (hue > (_5GY50[x] -0.035))) {correction = _5GY50[y] - _5GY50[x] ; lbe=_5GY50[y];correctL=true;} - } - else if (lum <65.0) { - if( (hue <= (_7G60[x] + 0.035)) && (hue > (_7G60[x] + _5G60[x])/2.0) ) {correction = _7G60[y] - _7G60[x] ;lbe=_7G60[y];correctL=true;} - else if( (hue <= (_7G60[x] + _5G60[x])/2.0) && (hue >(_5G60[x] + _25G60[x])/2.0)) {correction = _5G60[y] - _5G60[x] ;lbe=_5G60[y];correctL=true;} - else if (( hue<=(_25G60[x] + _5G60[x])/2.0) && (hue > (_25G60[x] + _1G60[x])/2.0)) {correction = _25G60[y] - _25G60[x] ;lbe=_25G60[y];correctL=true;} - else if (( hue<=(_1G60[x] + _25G60[x])/2.0) && (hue > (_1G60[x] + _10GY60[x])/2.0)) {correction = _1G60[y] - _1G60[x] ; lbe=_1G60[y];correctL=true;} - else if (( hue<=(_1G60[x] + _10GY60[x])/2.0) && (hue > (_10GY60[x] + _75GY60[x])/2.0)) {correction = _10GY60[y] - _10GY60[x] ;lbe= _10GY60[y];correctL=true;} - else if (( hue<=(_10GY60[x] + _75GY60[x])/2.0) && (hue > (_75GY60[x] + _5GY60[x])/2.0)) {correction = _75GY60[y] - _75GY60[x] ;lbe=_75GY60[y] ;correctL=true;} - else if (( hue<=(_5GY60[x] + _75GY60[x])/2.0) && (hue > (_5GY60[x] -0.035))) {correction = _5GY60[y] - _5GY60[x] ; lbe=_5GY60[y];correctL=true;} - } - else if (lum <75.0) { - if( (hue <= (_7G70[x] + 0.035)) && (hue > (_7G70[x] + _5G70[x])/2.0) ) {correction = _7G70[y] - _7G70[x] ;lbe= _7G70[y];correctL=true;} - else if( (hue <= (_7G70[x] + _5G70[x])/2.0) && (hue >(_5G70[x] + _25G70[x])/2.0)) {correction = _5G70[y] - _5G70[x] ;lbe= _5G70[y];correctL=true;} - else if (( hue<=(_25G70[x] + _5G70[x])/2.0) && (hue > (_25G70[x] + _1G70[x])/2.0)) {correction = _25G70[y] - _25G70[x] ;lbe=_25G70[y];correctL=true;} - else if (( hue<=(_1G70[x] + _25G70[x])/2.0) && (hue > (_1G70[x] + _10GY70[x])/2.0)) {correction = _1G70[y] - _1G70[x] ;lbe= _1G70[y] ;correctL=true;} - else if (( hue<=(_1G70[x] + _10GY70[x])/2.0) && (hue > (_10GY70[x] + _75GY70[x])/2.0)) {correction = _10GY70[y] - _10GY70[x] ; lbe=_10GY70[y];correctL=true;} - else if (( hue<=(_10GY70[x] + _75GY70[x])/2.0) && (hue > (_75GY70[x] + _5GY70[x])/2.0)) {correction = _75GY70[y] - _75GY70[x] ;lbe=_75GY70[y];correctL=true;} - else if (( hue<=(_5GY70[x] + _75GY70[x])/2.0) && (hue > (_5GY70[x] -0.035))) {correction = _5GY70[y] - _5GY70[x] ;lbe= _5GY70[y];correctL=true;} - } - else if (lum <85.0) { - if( (hue <= (_7G80[x] + 0.035)) && (hue > (_7G80[x] + _5G80[x])/2.0) ) {correction = _7G80[y] - _7G80[x] ;lbe=_7G80[y];correctL=true;} - else if( (hue <= (_7G80[x] + _5G80[x])/2.0) && (hue >(_5G80[x] + _25G80[x])/2.0)) {correction = _5G80[y] - _5G80[x] ;lbe=_5G80[y];correctL=true;} - else if (( hue<=(_25G80[x] + _5G80[x])/2.0) && (hue > (_25G80[x] + _1G80[x])/2.0)) {correction = _25G80[y] - _25G80[x] ;lbe=_25G80[y];correctL=true;} - else if (( hue<=(_1G80[x] + _25G80[x])/2.0) && (hue > (_1G80[x] + _10GY80[x])/2.0)) {correction = _1G80[y] - _1G80[x] ; lbe= _1G80[y];correctL=true;} - else if (( hue<=(_1G80[x] + _10GY80[x])/2.0) && (hue > (_10GY80[x] + _75GY80[x])/2.0)) {correction = _10GY80[y] - _10GY80[x] ;lbe=_10GY80[y];correctL=true; } - else if (( hue<=(_10GY80[x] + _75GY80[x])/2.0) && (hue > (_75GY80[x] + _5GY80[x])/2.0)) {correction = _75GY80[y] - _75GY80[x] ;lbe=_75GY80[y];correctL=true;} - else if (( hue<=(_5GY80[x] + _75GY80[x])/2.0) && (hue > (_5GY80[x] -0.035))) {correction = _5GY80[y] - _5GY80[x] ; lbe=_5GY80[y];correctL=true;} - } - } - } - //end green yellow - - //Red purple correction : only for L < 30 - else if(zone==4) { - if (lum > 5.0) { - if (lum < 15.0) { - if( (hue <= (_5R10[x] + 0.035)) && (hue > (_5R10[x] - 0.043)) && x<45) {if(y>44) y=44;correction = _5R10[y] - _5R10[x] ;lbe=_5R10[y];correctL=true;} - else if( (hue <= (_25R10[x] + 0.043)) && (hue >(_25R10[x] + _10RP10[x])/2.0) && x<45 ) {if(y>44) y=44;correction = _25R10[y] - _25R10[x] ;lbe= _25R10[y];correctL=true;} - else if ( (hue <=(_25R10[x] + _10RP10[x])/2.0) && (hue > (_10RP10[x] -0.035) ) && x<45){if(y>44) y=44; correction = _10RP10[y] - _10RP10[x] ;lbe=_10RP10[y];correctL=true;} - } - else if (lum <25.0) { - if( (hue <= (_5R20[x] + 0.035)) && (hue > (_5R20[x] + _25R20[x])/2.0) && x<70 ) {if(y>70) y=70;correction = _5R20[y] - _5R20[x] ;lbe= _5R20[y];correctL=true;} - else if( (hue <= (_5R20[x] + _25R20[x])/2.0) && (hue >(_10RP20[x] + _25R20[x])/2.0) && x<70) {if(y>70) y=70;correction = _25R20[y] - _25R20[x] ;lbe=_25R20[y];correctL=true;} - else if (( hue<=(_10RP20[x] + _25R20[x])/2.0) && (hue > (_10RP20[x] -0.035)) && x<70) {if(y>70) y=70; correction = _10RP20[y] - _10RP20[x] ;lbe=_10RP20[y];correctL=true;} - } - else if (lum <35.0) { - if( (hue <= (_5R30[x] + 0.035)) && (hue > (_5R30[x] + _25R30[x])/2.0) && x<85 ) {if(y>85) y=85;correction = _5R30[y] - _5R30[x] ;lbe= _5R30[y];correctL=true;} - else if( (hue <= (_5R30[x] + _25R30[x])/2.0) && (hue >(_10RP30[x] + _25R30[x])/2.0) && x< 85) {if(y>85) y=85;correction = _25R30[y] - _25R30[x] ;lbe=_25R30[y];correctL=true;} - else if (( hue<=(_10RP30[x] + _25R30[x])/2.0) && (hue > (_10RP30[x] -0.035)) && x<85) {if(y>85) y=85; correction = _10RP30[y] - _10RP30[x] ;lbe= _10RP30[y];correctL=true;} - } - } - } - //end red purple - } - - - /* - * SkinSat - * Copyright (c)2011 Jacques Desmis - * - * skin color: mixed from NX2 skin color palette, Von Luschan, and photos of people white, - * black, yellow....there are some little exceptions...cover 99% case - * pay attention to white balance, and do not change hue and saturation, upstream of the modification - * - */ - void Color::SkinSat (float lum, float hue, float chrom, float &satreduc) { - - // to be adapted...by tests - float reduction=0.3f; // use "reduction" for "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1 - float extendedreduction=0.4f; // use "extendedreduction" for wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation - float extendedreduction2=0.6f; // use "extendedreduction2" for wide area for transition - - float C9=8.0, C8=15.0, C7=12.0, C4=7.0, C3=5.0, C2=5.0, C1=5.0; - float H9=0.05, H8=0.25, H7=0.1, H4=0.02, H3=0.02, H2=0.1, H1=0.1, H10=-0.2,H11=-0.2; //H10 and H11 are curious...H11=-0.8 ?? - - if (lum >= 85.f) { - if((hue > (0.78f-H9) && hue < (1.18f+H9)) && (chrom > 8.f && chrom < (14.f+C9))) satreduc=reduction; - else if (lum >= 92.f) { - if((hue > 0.8f && hue < 1.65f) && (chrom > 7.f && chrom < (15.f))) satreduc=extendedreduction; - else if ((hue > -0.1f && hue < 1.65f) && (chrom > 7.f && chrom < (18.f))) satreduc=extendedreduction2; - } - else if ((hue > 0.7f && hue < 1.4f) && (chrom > 7.f && chrom < (26.f+C9))) satreduc=extendedreduction; - else if (lum < 92.f && (hue > 0.f && hue < 1.65f) && (chrom > 7.f && chrom < (35.f+C9))) satreduc=extendedreduction2; - } - else if (lum >= 70.f) { - if((hue > 0.4f && hue < (1.04f+H8)) && (chrom > 8.f && chrom < (35.f+C8))) satreduc=reduction; - else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; - else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; - } - else if (lum >= 52.f) { - if((hue > 0.3f && hue < (1.27f+H7)) && (chrom > 11.f && chrom < (35.f+C7))) satreduc=reduction; - else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; - else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; - } - else if (lum >= 35.f) { - if((hue > 0.3f && hue < (1.25f+H4)) && (chrom > 13.f && chrom < (37.f+C4))) satreduc=reduction; - else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; - else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; - } - else if (lum >= 20.f) { - if((hue > 0.3f && hue < (1.2f+H3)) && (chrom > 7.f && chrom <(35.f+C3) )) satreduc=reduction; - else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; - else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; - } - else if (lum > 10.f) { - if((hue > (0.f + H10) && hue < (0.95f +H2)) && (chrom > 8.f && chrom < (23.f+C2))) satreduc=reduction; - else if ((hue > (0.02f+H11) && hue < 1.f) && (chrom > 7.f && chrom < (35.f+C1) )) satreduc=extendedreduction; - else if ((hue > (0.02f+H11) && hue < 1.6f) && (chrom > 7.f && chrom < (45.f+C1) )) satreduc=extendedreduction2; - } - else { - if((hue > (0.02f + H10) && hue < (0.9f+H1)) && (chrom > 8.f && chrom < (23.f+C1))) satreduc=reduction; // no data : extrapolate - else if ((hue > (0.02f+H11) && hue < 1.f) && (chrom > 7.f && chrom < (35.f+C1) )) satreduc=extendedreduction; - else if ((hue > (0.02f+H11) && hue < 1.6f) && (chrom > 7.f && chrom < (45.f+C1) )) satreduc=extendedreduction2; - - } - - } - - /* - * Munsell Lch correction - * Copyright (c) 2011 Jacques Desmis - * - * data (Munsell ==> Lab) obtained with WallKillcolor and http://www.cis.rit.edu/research/mcsl2/online/munsell.php - * each LUT give Hue in function of C, for each color Munsell and Luminance - * eg: _6PB20 : color Munsell 6PB for L=20 c=5 c=45 c=85 c=125..139 when possible: interpolation betwwen values - * no value for C<5 (gray) - * low memory footprint -- maximum: 195 LUTf * 140 values - * errors due to small number of samples in LUT and linearization are very low (1 to 2%) - * errors due to a different illuminant "Daylight" than "C" are low, about 10%. For example, a theoretical correction of 0.1 radian will be made with a real correction of 0.09 or 0.11 depending on the color illuminant D50 - * errors due to the use of a very different illuminant "C", for example illuminant "A" (tungsten) are higher, about 20%. Theoretical correction of 0.52 radians will be made with a real correction of 0.42 - */ - void Color::initMunsell () { - #ifdef _DEBUG - MyTime t1e,t2e; - t1e.set(); - #endif - - const int maxInd = 140; - const int maxInd2 = 90; - const int maxInd3 = 50; - - //blue for sky - _5B40(maxInd2); - _5B40.clear(); - for (int i=0; i5) _5B40[i] = -2.3 + 0.0025*(i-5); - else if (i<90 && i>=45) _5B40[i] = -2.2 + 0.00*(i-45); - } - //printf("5B %1.2f %1.2f\n",_5B40[44],_5B40[89]); - _5B50(maxInd2); - _5B50.clear(); - for (int i=0; i5) _5B50[i] = -2.34 + 0.0025*(i-5); - else if (i<90 && i>=45) _5B50[i] = -2.24+0.0003*(i-45); - } - //printf("5B %1.2f %1.2f\n",_5B50[44],_5B50[89]); - _5B60(maxInd2); - _5B60.clear(); - for (int i=0; i5) _5B60[i] = -2.4 + 0.003*(i-5); - else if (i<90 && i>=45) _5B60[i] = -2.28+0.0005*(i-45); - } - //printf("5B %1.2f %1.2f\n",_5B60[44],_5B60[89]); - _5B70(maxInd2); - _5B70.clear(); - for (int i=0; i5) _5B70[i] = -2.41 + 0.00275*(i-5); - else if (i<90 && i>=45) _5B70[i] = -2.30+0.00025*(i-45); - } - //printf("5B %1.2f %1.2f\n",_5B70[44],_5B70[89]); - _5B80(maxInd3); - _5B80.clear(); - for (int i=0; i5) _5B80[i] = -2.45 +0.003*(i-5); - } - //printf("5B %1.2f\n",_5B80[49]); - - _7B40(maxInd2); - _7B40.clear(); - for (int i=0; i5) _7B40[i] = -2.15 + 0.0027*(i-5); - else if (i<90 && i>=45) _7B40[i] = -2.04 + 0.00*(i-45); - } - //printf("7B %1.2f %1.2f\n",_7B40[44],_7B40[89]); - _7B50(maxInd2); - _7B50.clear(); - for (int i=0; i5) _7B50[i] = -2.20 + 0.003*(i-5); - else if (i<90 && i>=45) _7B50[i] = -2.08 + 0.001*(i-45); - } - //printf("7B %1.2f %1.2f\n",_7B50[44],_7B50[79]); - _7B60(maxInd2); - _7B60.clear(); - for (int i=0; i5) _7B60[i] = -2.26 + 0.0035*(i-5); - else if (i<90 && i>=45) _7B60[i] = -2.12 + 0.001*(i-45); - } - //printf("7B %1.2f %1.2f\n",_7B60[44],_7B60[79]); - _7B70(maxInd2); - _7B70.clear(); - for (int i=0; i5) _7B70[i] = -2.28 + 0.003*(i-5); - else if (i<90 && i>=45) _7B70[i] = -2.16 + 0.0015*(i-45); - } - //printf("7B %1.2f %1.2f\n",_7B70[44],_7B70[64]); - _7B80(maxInd3); - _7B80.clear(); - for (int i=0; i5) _7B80[i] = -2.30 +0.0028*(i-5); - } - //printf("5B %1.2f\n",_7B80[49]); - - _9B40(maxInd2); - _9B40.clear(); - for (int i=0; i5) _9B40[i] = -1.99 + 0.0022*(i-5); - else if (i<90 && i>=45) _9B40[i] = -1.90 + 0.0008*(i-45); - } - //printf("9B %1.2f %1.2f\n",_9B40[44],_9B40[69]); - _9B50(maxInd2); - _9B50.clear(); - for (int i=0; i5) _9B50[i] = -2.04 + 0.0025*(i-5); - else if (i<90 && i>=45) _9B50[i] = -1.94 + 0.0013*(i-45); - } - //printf("9B %1.2f %1.2f\n",_9B50[44],_9B50[77]); - _9B60(maxInd2); - _9B60.clear(); - for (int i=0; i5) _9B60[i] = -2.10 + 0.0033*(i-5); - else if (i<90 && i>=45) _9B60[i] = -1.97 + 0.001*(i-45); - } - //printf("9B %1.2f %1.2f\n",_9B60[44],_9B60[79]); - _9B70(maxInd2); - _9B70.clear(); - for (int i=0; i5) _9B70[i] = -2.12 + 0.003*(i-5); - else if (i<90 && i>=45) _9B70[i] = -2.00 + 0.001*(i-45); - } - //printf("9B %1.2f %1.2f\n",_9B70[44],_9B70[54]); - _9B80(maxInd3); - _9B80.clear(); - for (int i=0; i5) _9B80[i] = -2.16 +0.0025*(i-5); - } - //printf("9B %1.2f\n",_9B80[49]); - - _10B40(maxInd2); - _10B40.clear(); - for (int i=0; i5) _10B40[i] = -1.92 + 0.0022*(i-5); - else if (i<90 && i>=45) _10B40[i] = -1.83 + 0.0012*(i-45); - } - //printf("10B %1.2f %1.2f\n",_10B40[44],_10B40[76]); - _10B50(maxInd2); - _10B50.clear(); - for (int i=0; i5) _10B50[i] = -1.95 + 0.0022*(i-5); - else if (i<90 && i>=45) _10B50[i] = -1.86 + 0.0008*(i-45); - } - //printf("10B %1.2f %1.2f\n",_10B50[44],_10B50[85]); - _10B60(maxInd2); - _10B60.clear(); - for (int i=0; i5) _10B60[i] = -2.01 + 0.0027*(i-5); - else if (i<90 && i>=45) _10B60[i] = -1.90 + 0.0012*(i-45); - } - //printf("10B %1.2f %1.2f\n",_10B60[44],_10B60[70]); - _10B70(maxInd3); - _10B70.clear(); - for (int i=0; i5) _10B70[i] = -2.03 +0.0025*(i-5); - } - //printf("10B %1.2f\n",_10B70[49]); - _10B80(maxInd3); - _10B80.clear(); - for (int i=0; i5) _10B80[i] = -2.08 +0.0032*(i-5); - } - //printf("10B %1.2f\n",_10B80[39]); - - _05PB40(maxInd2); - _05PB40.clear(); - for (int i=0; i5) _05PB40[i] = -1.87 + 0.0022*(i-5); - else if (i<90 && i>=45) _05PB40[i] = -1.78 + 0.0015*(i-45); - } - //printf("05PB %1.2f %1.2f\n",_05PB40[44],_05PB40[74]); - _05PB50(maxInd2); - _05PB50.clear(); - for (int i=0; i5) _05PB50[i] = -1.91 + 0.0022*(i-5); - else if (i<90 && i>=45) _05PB50[i] = -1.82 + 0.001*(i-45); - } - //printf("05PB %1.2f %1.2f\n",_05PB50[44],_05PB50[85]); - _05PB60(maxInd2); - _05PB60.clear(); - for (int i=0; i5) _05PB60[i] = -1.96 + 0.0027*(i-5); - else if (i<90 && i>=45) _05PB60[i] = -1.85 + 0.0013*(i-45); - } - //printf("05PB %1.2f %1.2f\n",_05PB60[44],_05PB60[70]); - _05PB70(maxInd2); - _05PB70.clear(); - for (int i=0; i5) _05PB70[i] = -1.99 + 0.0027*(i-5); - else if (i<90 && i>=45) _05PB70[i] = -1.88 + 0.001*(i-45); - } - //printf("05PB %1.2f %1.2f\n",_05PB70[44],_05PB70[54]); - _05PB80(maxInd3); - _05PB80.clear(); - for (int i=0; i5) _05PB80[i] = -2.03 +0.003*(i-5); - } - //printf("05PB %1.2f\n",_05PB80[39]); - - - - //blue purple correction - //between 15PB to 4P - //maximum deviation 75PB - - //15PB - _15PB10(maxInd3); - _15PB10.clear(); - for (int i=0; i5) _15PB10[i] = -1.66 +0.0035*(i-5); - } - //printf("15 %1.2f\n",_15PB10[49]); - _15PB20(maxInd2); - _15PB20.clear(); - for (int i=0; i5) _15PB20[i] = -1.71 +0.00275*(i-5); - else if (i<90 && i>=45) _15PB20[i] = -1.60+0.0012*(i-45); - } - //printf("15 %1.2f %1.2f\n",_15PB20[44],_15PB20[89]); - - _15PB30(maxInd2); - _15PB30.clear(); - for (int i=0; i5) _15PB30[i] = -1.75 +0.0025*(i-5); - else if (i<90 && i>=45) _15PB30[i] = -1.65+0.002*(i-45); - } - //printf("15 %1.2f %1.2f\n",_15PB30[44],_15PB30[89]); - - _15PB40(maxInd2); - _15PB40.clear(); - for (int i=0; i5) _15PB40[i] = -1.79 +0.002*(i-5); - else if (i<90 && i>=45) _15PB40[i] = -1.71+0.002*(i-45); - } - //printf("15 %1.2f %1.2f\n",_15PB40[44],_15PB40[89]); - - _15PB50(maxInd2); - _15PB50.clear(); - for (int i=0; i5) _15PB50[i] = -1.82 +0.002*(i-5); - else if (i<90 && i>=45) _15PB50[i] = -1.74+0.0011*(i-45); - } - //printf("15 %1.2f %1.2f\n",_15PB50[44],_15PB50[89]); - - _15PB60(maxInd2); - _15PB60.clear(); - for (int i=0; i5) _15PB60[i] = -1.87 +0.0025*(i-5); - else if (i<90 && i>=45) _15PB60[i] = -1.77+0.001*(i-45); - } - //printf("15 %1.2f %1.2f\n",_15PB60[44],_15PB60[89]); - _15PB70(maxInd3); - _15PB70.clear(); - for (int i=0; i5) _15PB70[i] = -1.90 +0.0027*(i-5); - } - // printf("15 %1.2f\n",_15PB70[49]); - _15PB80(maxInd3); - _15PB80.clear(); - for (int i=0; i5) _15PB80[i] = -1.93 +0.0027*(i-5); - } - //printf("15 %1.2f %1.2f\n",_15PB80[38], _15PB80[49]); - - //3PB - _3PB10(maxInd2); - _3PB10.clear(); - for (int i=0; i5) _3PB10[i] = -1.56 +0.005*(i-5); - else if (i<90 && i>=45) _3PB10[i] = -1.36+0.001*(i-45); - } - //printf("30 %1.2f %1.2f\n",_3PB10[44],_3PB10[89]); - - _3PB20(maxInd2); - _3PB20.clear(); - for (int i=0; i5) _3PB20[i] = -1.59 +0.00275*(i-5); - else if (i<90 && i>=45) _3PB20[i] = -1.48+0.003*(i-45); - } - //printf("30 %1.2f %1.2f\n",_3PB20[44],_3PB20[89]); - - _3PB30(maxInd2); - _3PB30.clear(); - for (int i=0; i5) _3PB30[i] = -1.62 +0.00225*(i-5); - else if (i<90 && i>=45) _3PB30[i] = -1.53+0.0032*(i-45); - } - //printf("30 %1.2f %1.2f\n",_3PB30[44],_3PB30[89]); - - _3PB40(maxInd2); - _3PB40.clear(); - for (int i=0; i5) _3PB40[i] = -1.64 +0.0015*(i-5); - else if (i<90 && i>=45) _3PB40[i] = -1.58+0.0025*(i-45); - } - //printf("30 %1.2f %1.2f\n",_3PB40[44],_3PB40[89]); - - _3PB50(maxInd2); - _3PB50.clear(); - for (int i=0; i5) _3PB50[i] = -1.69 +0.00175*(i-5); - else if (i<90 && i>=45) _3PB50[i] = -1.62+0.002*(i-45); - } - //printf("30 %1.2f %1.2f\n",_3PB50[44],_3PB50[89]); - - _3PB60(maxInd2); - _3PB60.clear(); - for (int i=0; i5) _3PB60[i] = -1.73 +0.002*(i-5); - else if (i<90 && i>=45) _3PB60[i] = -1.65+0.0012*(i-45); - } - //printf("30 %1.2f %1.2f\n",_3PB60[44],_3PB60[89]); - _3PB70(maxInd3); - _3PB70.clear(); - for (int i=0; i5) _3PB70[i] = -1.76 +0.002*(i-5); - } - //printf("30 %1.2f\n",_3PB70[49]); - _3PB80(maxInd3); - _3PB80.clear(); - for (int i=0; i5) _3PB80[i] = -1.78 +0.0025*(i-5); - } - //printf("30 %1.2f %1.2f\n",_3PB80[38], _3PB80[49]); - - //45PB - _45PB10(maxInd2); - _45PB10.clear(); - for (int i=0; i5) _45PB10[i] = -1.46 +0.0045*(i-5); - else if (i<90 && i>=45) _45PB10[i] = -1.28+0.0025*(i-45); - } - //printf("45 %1.2f %1.2f\n",_45PB10[44],_45PB10[89]); - - _45PB20(maxInd2); - _45PB20.clear(); - for (int i=0; i5) _45PB20[i] = -1.48 +0.00275*(i-5); - else if (i<90 && i>=45) _45PB20[i] = -1.37+0.0025*(i-45); - } - //printf("45 %1.2f %1.2f\n",_45PB20[44],_45PB20[89]); - - _45PB30(maxInd2); - _45PB30.clear(); - for (int i=0; i5) _45PB30[i] = -1.51 +0.00175*(i-5); - else if (i<90 && i>=45) _45PB30[i] = -1.44+0.0035*(i-45); - } - //printf("45 %1.2f %1.2f\n",_45PB30[44],_45PB30[89]); - - _45PB40(maxInd2); - _45PB40.clear(); - for (int i=0; i5) _45PB40[i] = -1.52 +0.001*(i-5); - else if (i<90 && i>=45) _45PB40[i] = -1.48+0.003*(i-45); - } - //printf("45 %1.2f %1.2f\n",_45PB40[44],_45PB40[89]); - - _45PB50(maxInd2); - _45PB50.clear(); - for (int i=0; i5) _45PB50[i] = -1.55 +0.001*(i-5); - else if (i<90 && i>=45) _45PB50[i] = -1.51+0.0022*(i-45); - } - //printf("45 %1.2f %1.2f\n",_45PB50[44],_45PB50[89]); - - _45PB60(maxInd2); - _45PB60.clear(); - for (int i=0; i5) _45PB60[i] = -1.6 +0.0015*(i-5); - else if (i<90 && i>=45) _45PB60[i] = -1.54+0.001*(i-45); - } - //printf("45 %1.2f %1.2f\n",_45PB60[44],_45PB60[89]); - _45PB70(maxInd3); - _45PB70.clear(); - for (int i=0; i5) _45PB70[i] = -1.63 +0.0017*(i-5); - } - //printf("45 %1.2f\n",_45PB70[49]); - _45PB80(maxInd3); - _45PB80.clear(); - for (int i=0; i5) _45PB80[i] = -1.67 +0.0025*(i-5); - } - //printf("45 %1.2f %1.2f\n",_45PB80[38], _45PB80[49]); - - //_6PB - _6PB10(maxInd); - _6PB10.clear(); - for (int i=0; i140 - if (i<45 && i>5) _6PB10[i] = -1.33 +0.005*(i-5); - else if (i<85 && i>=45) _6PB10[i] = -1.13+0.0045*(i-45); - else if (i<140 && i >=85) _6PB10[i] = -0.95+0.0015*(i-85); - } - //printf("60 %1.2f %1.2f %1.2f\n",_6PB10[44],_6PB10[84],_6PB10[139]); - - _6PB20(maxInd); - _6PB20.clear(); - for (int i=0; i140 - if (i<45 && i>5) _6PB20[i] = -1.36 +0.004*(i-5); - else if (i<85 && i>=45) _6PB20[i] = -1.20+0.00375*(i-45); - else if (i<140 && i >=85) _6PB20[i] = -1.05+0.0017*(i-85); - } - //printf("60 %1.2f %1.2f %1.2f\n",_6PB20[44],_6PB20[84],_6PB20[139]); - - _6PB30(maxInd); - _6PB30.clear(); - for (int i=0; i140 - if (i<45 && i>5) _6PB30[i] = -1.38 +0.00225*(i-5); - else if (i<85 && i>=45) _6PB30[i] = -1.29+0.00375*(i-45); - else if (i<140 && i >=85) _6PB30[i] = -1.14+0.002*(i-85); - } - //printf("60 %1.2f %1.2f %1.2f\n",_6PB30[44],_6PB30[84],_6PB30[139]); - - _6PB40(maxInd); - _6PB40.clear(); - for (int i=0; i140 - if (i<45 && i>5) _6PB40[i] = -1.39 +0.00125*(i-5); - else if (i<85 && i>=45) _6PB40[i] = -1.34+0.00275*(i-45); - else if (i<140 && i >=85) _6PB40[i] = -1.23+0.002*(i-85); - } - //printf("60 %1.2f %1.2f %1.2f\n",_6PB40[44],_6PB40[84],_6PB40[139]); - - _6PB50(maxInd2);//limits -1.3 -1.11 - _6PB50.clear(); - for (int i=0; i5) _6PB50[i] = -1.43 +0.00125*(i-5); - else if (i<90 && i>=45) _6PB50[i] = -1.38+0.00225*(i-45); - } - //printf("60 %1.2f %1.2f \n",_6PB50[44],_6PB50[89]); - - _6PB60(maxInd2);//limits -1.3 -1.11 - _6PB60.clear(); - for (int i=0; i5) _6PB60[i] = -1.46 +0.0012*(i-5); - else if (i<90 && i>=45) _6PB60[i] = -1.40+0.000875*(i-45); - } - //printf("60 %1.2f %1.2f\n",_6PB60[44],_6PB60[89]); - _6PB70(maxInd3); - _6PB70.clear(); - for (int i=0; i5) _6PB70[i] = -1.49 +0.0018*(i-5); - } - //printf("6 %1.2f\n",_6PB70[49]); - _6PB80(maxInd3); - _6PB80.clear(); - for (int i=0; i5) _6PB80[i] = -1.52 +0.0022*(i-5); - } - //printf("6 %1.2f %1.2f\n",_6PB80[38], _6PB80[49]); - - - //_75PB : notation Munsell for maximum deviation blue purple - _75PB10(maxInd);//limits hue -1.23 -0.71 _75PBx x=Luminance eg_75PB10 for L >5 and L<=15 - _75PB10.clear(); - for (int i=0; i140 - if (i<45 && i>5) _75PB10[i] = -1.23 +0.0065*(i-5); - else if (i<85 && i>=45) _75PB10[i] = -0.97+0.00375*(i-45); - else if (i<140 && i >=85) _75PB10[i] = -0.82+0.0015*(i-85); - } - //printf("75 %1.2f %1.2f %1.2f\n",_75PB10[44],_75PB10[84],_75PB10[139]); - - _75PB20(maxInd);//limits -1.24 -0.79 for L>15 <=25 - _75PB20.clear(); - for (int i=0; i5) _75PB20[i] = -1.24 +0.004*(i-5); - else if (i<85 && i>=45) _75PB20[i] = -1.08+0.00425*(i-45); - else if (i<140 && i >=85) _75PB20[i] = -0.91+0.0017*(i-85); - } - //printf("75 %1.2f %1.2f %1.2f\n",_75PB20[44],_75PB20[84],_75PB20[139]); - - _75PB30(maxInd);//limits -1.25 -0.85 - _75PB30.clear(); - for (int i=0; i5) _75PB30[i] = -1.25 +0.00275*(i-5); - else if (i<85 && i>=45) _75PB30[i] = -1.14+0.004*(i-45); - else if (i<140 && i >=85) _75PB30[i] = -0.98+0.0015*(i-85); - } - //printf("75 %1.2f %1.2f %1.2f\n",_75PB30[44],_75PB30[84],_75PB30[139]); - - _75PB40(maxInd);//limits -1.27 -0.92 - _75PB40.clear(); - for (int i=0; i5) _75PB40[i] = -1.27 +0.002*(i-5); - else if (i<85 && i>=45) _75PB40[i] = -1.19+0.003*(i-45); - else if (i<140 && i >=85) _75PB40[i] = -1.07+0.0022*(i-85); - } - //printf("75 %1.2f %1.2f %1.2f\n",_75PB40[44],_75PB40[84],_75PB40[139]); - - _75PB50(maxInd2);//limits -1.3 -1.11 - _75PB50.clear(); - for (int i=0; i5) _75PB50[i] = -1.3 +0.00175*(i-5); - else if (i<90 && i>=45) _75PB50[i] = -1.23+0.0025*(i-45); - } - //printf("75 %1.2f %1.2f\n",_75PB50[44],_75PB50[89]); - - _75PB60(maxInd2); - _75PB60.clear(); - for (int i=0; i5) _75PB60[i] = -1.32 +0.0015*(i-5); - else if (i<90 && i>=45) _75PB60[i] = -1.26+0.002*(i-45); - } - //printf("75 %1.2f %1.2f \n",_75PB60[44],_75PB60[89]); - - _75PB70(maxInd3); - _75PB70.clear(); - for (int i=0; i5) _75PB70[i] = -1.34 +0.002*(i-5); - } - _75PB80(maxInd3); - _75PB80.clear(); - for (int i=0; i5) _75PB80[i] = -1.35 +0.00125*(i-5); - } - - - _9PB10(maxInd); - _9PB10.clear(); - for (int i=0; i140 - if (i<45 && i>5) _9PB10[i] = -1.09 +0.00475*(i-5); - else if (i<85 && i>=45) _9PB10[i] = -0.9+0.003*(i-45); - else if (i<140 && i >=85) _9PB10[i] = -0.78+0.0013*(i-85); - } - //printf("90 %1.2f %1.2f %1.2f\n",_9PB10[44],_9PB10[84],_9PB10[139]); - - _9PB20(maxInd); - _9PB20.clear(); - for (int i=0; i140 - if (i<45 && i>5) _9PB20[i] = -1.12 +0.0035*(i-5); - else if (i<85 && i>=45) _9PB20[i] = -0.98+0.00325*(i-45); - else if (i<140 && i >=85) _9PB20[i] = -0.85+0.0015*(i-85); - } - //printf("90 %1.2f %1.2f %1.2f\n",_9PB20[44],_9PB20[84],_9PB20[139]); - - _9PB30(maxInd); - _9PB30.clear(); - for (int i=0; i140 - if (i<45 && i>5) _9PB30[i] = -1.14 +0.0028*(i-5); - else if (i<85 && i>=45) _9PB30[i] = -1.03+0.003*(i-45); - else if (i<140 && i >=85) _9PB30[i] = -0.91+0.0017*(i-85); - } - //printf("90 %1.2f %1.2f %1.2f\n",_9PB30[44],_9PB30[84],_9PB30[139]); - - _9PB40(maxInd); - _9PB40.clear(); - for (int i=0; i140 - if (i<45 && i>5) _9PB40[i] = -1.16 +0.002*(i-5); - else if (i<85 && i>=45) _9PB40[i] = -1.08+0.00275*(i-45); - else if (i<140 && i >=85) _9PB40[i] = -0.97+0.0016*(i-85); - } - //printf("90 %1.2f %1.2f %1.2f\n",_9PB40[44],_9PB40[84],_9PB40[139]); - - _9PB50(maxInd2); - _9PB50.clear(); - for (int i=0; i5) _9PB50[i] = -1.19 +0.00175*(i-5); - else if (i<90 && i>=45) _9PB50[i] = -1.12+0.00225*(i-45); - } - //printf("90 %1.2f %1.2f \n",_9PB50[44],_9PB50[84]); - - _9PB60(maxInd2); - _9PB60.clear(); - for (int i=0; i5) _9PB60[i] = -1.21 +0.0015*(i-5); - else if (i<90 && i>=45) _9PB60[i] = -1.15+0.002*(i-45); - } - //printf("90 %1.2f %1.2f \n",_9PB60[44],_9PB60[89]); - _9PB70(maxInd3); - _9PB70.clear(); - for (int i=0; i5) _9PB70[i] = -1.23 +0.0018*(i-5); - } - //printf("9 %1.2f\n",_9PB70[49]); - _9PB80(maxInd3); - _9PB80.clear(); - for (int i=0; i5) _9PB80[i] = -1.24 +0.002*(i-5); - } - //printf("9 %1.2f %1.2f\n",_9PB80[38], _9PB80[49]); - - - //10PB - _10PB10(maxInd); - _10PB10.clear(); - for (int i=0; i5) _10PB10[i] = -1.02 +0.00425*(i-5); - else if (i<85 && i>=45) _10PB10[i] = -0.85+0.0025*(i-45); - else if (i<140 && i >=85) _10PB10[i] = -0.75+0.0012*(i-85); - } - //printf("10 %1.2f %1.2f %1.2f\n",_10PB10[44],_10PB10[84],_10PB10[139]); - - _10PB20(maxInd); - _10PB20.clear(); - for (int i=0; i5) _10PB20[i] = -1.05 +0.00325*(i-5); - else if (i<85 && i>=45) _10PB20[i] = -0.92+0.00275*(i-45); - else if (i<140 && i >=85) _10PB20[i] = -0.81+0.0014*(i-85); - } - //printf("10 %1.2f %1.2f %1.2f\n",_10PB20[44],_10PB20[84],_10PB20[139]); - - _10PB30(maxInd); - _10PB30.clear(); - for (int i=0; i5) _10PB30[i] = -1.07 +0.00275*(i-5); - else if (i<85 && i>=45) _10PB30[i] = -0.96+0.0025*(i-45); - else if (i<140 && i >=85) _10PB30[i] = -0.86+0.0015*(i-85); - } - //printf("10 %1.2f %1.2f %1.2f\n",_10PB30[44],_10PB30[84],_10PB30[139]); - - _10PB40(maxInd); - _10PB40.clear(); - for (int i=0; i5) _10PB40[i] = -1.09 +0.002*(i-5); - else if (i<85 && i>=45) _10PB40[i] = -1.01+0.00225*(i-45); - else if (i<140 && i >=85) _10PB40[i] = -0.92+0.0016*(i-85); - } - //printf("10 %1.2f %1.2f %1.2f\n",_10PB40[44],_10PB40[84],_10PB40[139]); - - _10PB50(maxInd2); - _10PB50.clear(); - for (int i=0; i5) _10PB50[i] = -1.12 +0.00175*(i-5); - else if (i<90 && i>=45) _10PB50[i] = -1.05+0.00225*(i-45); - } - //printf("10 %1.2f %1.2f\n",_10PB50[44],_10PB50[84]); - - _10PB60(maxInd2); - _10PB60.clear(); - for (int i=0; i5) _10PB60[i] = -1.14 +0.0015*(i-5); - else if (i<90 && i>=45) _10PB60[i] = -1.08+0.00225*(i-45); - } - //printf("10 %1.2f %1.2f\n",_10PB60[44],_10PB60[89]); - - - //1P - _1P10(maxInd); - _1P10.clear(); - for (int i=0; i5) _1P10[i] = -0.96 +0.00375*(i-5); - else if (i<85 && i>=45) _1P10[i] = -0.81+0.00225*(i-45); - else if (i<140 && i >=85) _1P10[i] = -0.72+0.001*(i-85); - } - //printf("1P %1.2f %1.2f %1.2f\n",_1P10[44],_1P10[84],_1P10[139]); - - _1P20(maxInd); - _1P20.clear(); - for (int i=0; i5) _1P20[i] = -1.0 +0.00325*(i-5); - else if (i<85 && i>=45) _1P20[i] = -0.87+0.0025*(i-45); - else if (i<140 && i >=85) _1P20[i] = -0.77+0.0012*(i-85); - } - //printf("1P %1.2f %1.2f %1.2f\n",_1P20[44],_1P20[84],_1P20[139]); - - _1P30(maxInd); - _1P30.clear(); - for (int i=0; i5) _1P30[i] = -1.02 +0.00275*(i-5); - else if (i<85 && i>=45) _1P30[i] = -0.91+0.00225*(i-45); - else if (i<140 && i >=85) _1P30[i] = -0.82+0.0011*(i-85); - } - //printf("1P %1.2f %1.2f %1.2f\n",_1P30[44],_1P30[84],_1P30[139]); - - _1P40(maxInd); - _1P40.clear(); - for (int i=0; i5) _1P40[i] = -1.04 +0.00225*(i-5); - else if (i<85 && i>=45) _1P40[i] = -0.95+0.00225*(i-45); - else if (i<140 && i >=85) _1P40[i] = -0.86+0.0015*(i-85); - } - //printf("1P %1.2f %1.2f %1.2f\n",_1P40[44],_1P40[84],_1P40[139]); - - _1P50(maxInd2); - _1P50.clear(); - for (int i=0; i5) _1P50[i] = -1.06 +0.002*(i-5); - else if (i<90 && i>=45) _1P50[i] = -0.98+0.00175*(i-45); - } - //printf("1P %1.2f %1.2f \n",_1P50[44],_1P50[89]); - - _1P60(maxInd2); - _1P60.clear(); - for (int i=0; i5) _1P60[i] = -1.07 +0.0015*(i-5); - else if (i<90 && i>=45) _1P60[i] = -1.01+0.00175*(i-45); - } - //printf("1P %1.2f %1.2f \n",_1P60[44],_1P60[84],_1P60[139]); - - //4P - _4P10(maxInd); - _4P10.clear(); - for (int i=0; i5) _4P10[i] = -0.78 +0.002*(i-5); - else if (i<85 && i>=45) _4P10[i] = -0.7+0.00125*(i-45); - else if (i<140 && i >=85) _4P10[i] = -0.65+0.001*(i-85); - } - //printf("4P %1.2f %1.2f %1.2f\n",_4P10[44],_4P10[84],_4P10[139]); - - _4P20(maxInd); - _4P20.clear(); - for (int i=0; i5) _4P20[i] = -0.84 +0.0025*(i-5); - else if (i<85 && i>=45) _4P20[i] = -0.74+0.00175*(i-45); - else if (i<140 && i >=85) _4P20[i] = -0.67+0.00085*(i-85); - } - //printf("4P %1.2f %1.2f %1.2f\n",_4P20[44],_4P20[84],_4P20[139]); - - _4P30(maxInd); - _4P30.clear(); - for (int i=0; i5) _4P30[i] = -0.85 +0.00225*(i-5); - else if (i<85 && i>=45) _4P30[i] = -0.76+0.00125*(i-45); - else if (i<140 && i >=85) _4P30[i] = -0.71+0.001*(i-85); - } - //printf("4P %1.2f %1.2f %1.2f\n",_4P30[44],_4P30[84],_4P30[139]); - - _4P40(maxInd); - _4P40.clear(); - for (int i=0; i5) _4P40[i] = -0.87 +0.00175*(i-5); - else if (i<85 && i>=45) _4P40[i] = -0.8+0.00175*(i-45); - else if (i<140 && i >=85) _4P40[i] = -0.73+0.00075*(i-85); - } - //printf("4P %1.2f %1.2f %1.2f\n",_4P40[44],_4P40[84],_4P40[139]); - - _4P50(maxInd2); - _4P50.clear(); - for (int i=0; i5) _4P50[i] = -0.88 +0.0015*(i-5); - else if (i<90 && i>=45) _4P50[i] = -0.82+0.0015*(i-45); - } - //printf("4P %1.2f %1.2f \n",_4P50[44],_4P50[89]); - - _4P60(maxInd2); - _4P60.clear(); - for (int i=0; i5) _4P60[i] = -0.89 +0.00125*(i-5); - else if (i<90 && i>=45) _4P60[i] = -0.84+0.00125*(i-45); - } - //printf("4P %1.2f %1.2f\n",_4P60[44],_4P60[89]); - - - //red yellow correction - _10YR20(maxInd2); - _10YR20.clear(); - for (int i=0; i5) _10YR20[i] = 1.22 +0.002*(i-5); - else if (i<90 && i>=45) _10YR20[i] = 1.30+0.006*(i-45); - } - //printf("10YR %1.2f %1.2f\n",_10YR20[44],_10YR20[56]); - _10YR30(maxInd2); - _10YR30.clear(); - for (int i=0; i5) _10YR30[i] = 1.27 +0.00175*(i-5); - else if (i<90 && i>=45) _10YR30[i] = 1.34+0.0017*(i-45); - } - //printf("10YR %1.2f %1.2f\n",_10YR30[44],_10YR30[75]); - _10YR40(maxInd2); - _10YR40.clear(); - for (int i=0; i5) _10YR40[i] = 1.32 +0.00025*(i-5); - else if (i<90 && i>=45) _10YR40[i] = 1.33+0.0015*(i-45); - } - //printf("10YR %1.2f %1.2f\n",_10YR40[44],_10YR40[85]); - _10YR50(maxInd2); - _10YR50.clear(); - for (int i=0; i5) _10YR50[i] = 1.35 +0.000*(i-5); - else if (i<90 && i>=45) _10YR50[i] = 1.35+0.0012*(i-45); - } - //printf("10YR %1.2f %1.2f\n",_10YR50[44],_10YR50[80]); - _10YR60(maxInd); - _10YR60.clear(); - for (int i=0; i5) _10YR60[i] = 1.38 - 0.00025*(i-5); - else if (i<85 && i>=45) _10YR60[i] = 1.37+0.0005*(i-45); - else if (i<140 && i >=85) _10YR60[i] = 1.39+0.0013*(i-85); - } - //printf("10YR %1.2f %1.2f %1.2f\n",_10YR60[44],_10YR60[85],_10YR60[139] ); - _10YR70(maxInd); - _10YR70.clear(); - for (int i=0; i5) _10YR70[i] = 1.41 - 0.0005*(i-5); - else if (i<85 && i>=45) _10YR70[i] = 1.39+0.000*(i-45); - else if (i<140 && i >=85) _10YR70[i] = 1.39+0.0013*(i-85); - } - //printf("10YR %1.2f %1.2f %1.2f\n",_10YR70[44],_10YR70[85],_10YR70[139] ); - _10YR80(maxInd); - _10YR80.clear(); - for (int i=0; i5) _10YR80[i] = 1.45 - 0.00125*(i-5); - else if (i<85 && i>=45) _10YR80[i] = 1.40+0.000*(i-45); - else if (i<140 && i >=85) _10YR80[i] = 1.40+0.00072*(i-85);//1.436 - } - //printf("10YR %1.2f %1.2f %1.2f\n",_10YR80[44],_10YR80[84],_10YR80[139] ); - _10YR90(maxInd2); - _10YR90.clear(); - for (int i=0; i5) _10YR90[i] = 1.48 -0.001*(i-5); - else if (i<90 && i>=45) _10YR90[i] = 1.44-0.0009*(i-45); - } - //printf("10YR %1.2f %1.2f\n",_10YR90[45],_10YR90[80]); - _85YR20(maxInd3); - _85YR20.clear(); - for (int i=0; i5) _85YR20[i] = 1.12 +0.004*(i-5); - } - - //printf("85YR %1.2f \n",_85YR20[44]); - _85YR30(maxInd2); - _85YR30.clear(); - for (int i=0; i5) _85YR30[i] = 1.16 + 0.0025*(i-5); - else if (i<90 && i>=45) _85YR30[i] = 1.26+0.0028*(i-45); - } - //printf("85YR %1.2f %1.2f\n",_85YR30[44],_85YR30[75]); - _85YR40(maxInd2); - _85YR40.clear(); - for (int i=0; i5) _85YR40[i] = 1.20 + 0.0015*(i-5); - else if (i<90 && i>=45) _85YR40[i] = 1.26+0.0024*(i-45); - } - //printf("85YR %1.2f %1.2f\n",_85YR40[44],_85YR40[75]); - _85YR50(maxInd); - _85YR50.clear(); - for (int i=0; i5) _85YR50[i] = 1.24 + 0.0005*(i-5); - else if (i<85 && i>=45) _85YR50[i] = 1.26+0.002*(i-45); - else if (i<140 && i >=85) _85YR50[i] = 1.34+0.0015*(i-85); - } - //printf("85YR %1.2f %1.2f %1.2f\n",_85YR50[44],_85YR50[85],_85YR50[110] ); - _85YR60(maxInd); - _85YR60.clear(); - for (int i=0; i5) _85YR60[i] = 1.27 + 0.00025*(i-5); - else if (i<85 && i>=45) _85YR60[i] = 1.28+0.0015*(i-45); - else if (i<140 && i >=85) _85YR60[i] = 1.34+0.0012*(i-85); - } - //printf("85YR %1.2f %1.2f %1.2f\n",_85YR60[44],_85YR60[85],_85YR60[139] ); - - _85YR70(maxInd); - _85YR70.clear(); - for (int i=0; i5) _85YR70[i] = 1.31 - 0.00025*(i-5); - else if (i<85 && i>=45) _85YR70[i] = 1.30+0.0005*(i-45); - else if (i<140 && i >=85) _85YR70[i] = 1.32+0.0012*(i-85); - } - //printf("85YR %1.2f %1.2f %1.2f\n",_85YR70[44],_85YR70[85],_85YR70[139] ); - _85YR80(maxInd); - _85YR80.clear(); - for (int i=0; i5) _85YR80[i] = 1.35 - 0.00075*(i-5); - else if (i<85 && i>=45) _85YR80[i] = 1.32+0.00025*(i-45); - else if (i<140 && i >=85) _85YR80[i] = 1.33+0.00125*(i-85); - } - //printf("85YR %1.2f %1.2f %1.2f\n",_85YR80[44],_85YR80[85],_85YR80[139] ); - _85YR90(maxInd2); - _85YR90.clear(); - for (int i=0; i5) _85YR90[i] = 1.39 - 0.00125*(i-5); - else if (i<90 && i>=45) _85YR90[i] = 1.34+0.00*(i-45); - } - //printf("85YR %1.2f %1.2f\n",_85YR90[44],_85YR90[85]); - - //7YR - _7YR30(maxInd2); - _7YR30.clear(); - for (int i=0; i5) _7YR30[i] = 1.06 + 0.0028*(i-5); - else if (i<90 && i>=45) _7YR30[i] = 1.17+0.0045*(i-45); - } - //printf("7YR %1.2f %1.2f\n",_7YR30[44],_7YR30[66]); - _7YR40(maxInd2); - _7YR40.clear(); - for (int i=0; i5) _7YR40[i] = 1.10 + 0.0018*(i-5); - else if (i<90 && i>=45) _7YR40[i] = 1.17+0.0035*(i-45); - } - //printf("7YR %1.2f %1.2f\n",_7YR40[44],_7YR40[89]); - _7YR50(maxInd2); - _7YR50.clear(); - for (int i=0; i5) _7YR50[i] = 1.14 + 0.00125*(i-5); - else if (i<90 && i>=45) _7YR50[i] = 1.19+0.002*(i-45); - } - //printf("7YR %1.2f %1.2f\n",_7YR50[44],_7YR50[89] ); - _7YR60(maxInd); - _7YR60.clear(); - for (int i=0; i5) _7YR60[i] = 1.17 + 0.00075*(i-5); - else if (i<85 && i>=45) _7YR60[i] = 1.20+0.00175*(i-45); - else if (i<140 && i >=85) _7YR60[i] = 1.27+0.002*(i-85); - } - //printf("7YR %1.2f %1.2f %1.2f\n",_7YR60[44],_7YR60[84],_7YR60[125] ); - - _7YR70(maxInd); - _7YR70.clear(); - for (int i=0; i5) _7YR70[i] = 1.20 + 0.0005*(i-5); - else if (i<85 && i>=45) _7YR70[i] = 1.22+0.00125*(i-45); - else if (i<140 && i >=85) _7YR70[i] = 1.27+0.0015*(i-85); - } - //printf("7YR %1.2f %1.2f %1.2f\n",_7YR70[44],_7YR70[84],_7YR70[125] ); - _7YR80(maxInd3); - _7YR80.clear(); - for (int i=0; i5) _7YR80[i] = 1.29 - 0.0008*(i-5); - } - //printf("7YR %1.2f \n",_7YR80[44] ); - _55YR30(maxInd3); - _55YR30.clear(); - for (int i=0; i5) _55YR30[i] = 0.96 + 0.0038*(i-5); - } - //printf("55YR %1.2f \n",_55YR30[44] ); - _55YR40(maxInd2); - _55YR40.clear(); - for (int i=0; i5) _55YR40[i] = 1.01 + 0.0022*(i-5); - else if (i<90 && i>=45) _55YR40[i] = 1.10+0.0037*(i-45); - } - //printf("55YR %1.2f %1.2f\n",_55YR40[44],_55YR40[89] ); - _55YR50(maxInd); - _55YR50.clear(); - for (int i=0; i5) _55YR50[i] = 1.06 + 0.0015*(i-5); - else if (i<85 && i>=45) _55YR50[i] = 1.12+0.00225*(i-45); - else if (i<140 && i >=85) _55YR50[i] = 1.21+0.0015*(i-85); - } - //printf("55YR %1.2f %1.2f %1.2f\n",_55YR50[44],_55YR50[84],_55YR50[125] ); - _55YR60(maxInd); - _55YR60.clear(); - for (int i=0; i5) _55YR60[i] = 1.08 + 0.0012*(i-5); - else if (i<85 && i>=45) _55YR60[i] = 1.13+0.0018*(i-45); - else if (i<140 && i >=85) _55YR60[i] = 1.20+0.0025*(i-85); - } - //printf("55YR %1.2f %1.2f %1.2f\n",_55YR60[44],_55YR60[84],_55YR60[125] ); - _55YR70(maxInd); - _55YR70.clear(); - for (int i=0; i5) _55YR70[i] = 1.11 + 0.00075*(i-5); - else if (i<85 && i>=45) _55YR70[i] = 1.14+0.0012*(i-45); - else if (i<140 && i >=85) _55YR70[i] = 1.19+0.00225*(i-85); - } - //printf("55YR %1.2f %1.2f %1.2f\n",_55YR70[44],_55YR70[84],_55YR70[125] ); - _55YR80(maxInd); - _55YR80.clear(); - for (int i=0; i5) _55YR80[i] = 1.16 + 0.00*(i-5); - else if (i<85 && i>=45) _55YR80[i] = 1.16+0.00075*(i-45); - else if (i<140 && i >=85) _55YR80[i] = 1.19+0.00175*(i-85); - } - //printf("55YR %1.2f %1.2f %1.2f\n",_55YR80[44],_55YR80[84],_55YR80[125] ); - _55YR90(maxInd3); - _55YR90.clear(); - for (int i=0; i5) _55YR90[i] = 1.19 - 0.0005*(i-5); - } - //printf("55YR %1.2f \n",_55YR90[44] ); - - _4YR30(maxInd2); - _4YR30.clear(); - for (int i=0; i5) _4YR30[i] = 0.87 + 0.0035*(i-5); - else if (i<90 && i>=45) _4YR30[i] = 1.01+0.0043*(i-45); - } - //printf("4YR %1.2f %1.2f\n",_4YR30[44],_4YR30[78] ); - _4YR40(maxInd2); - _4YR40.clear(); - for (int i=0; i5) _4YR40[i] = 0.92 + 0.0025*(i-5); - else if (i<90 && i>=45) _4YR40[i] = 1.02+0.0033*(i-45); - } - //printf("4YR %1.2f %1.2f\n",_4YR40[44],_4YR40[74] ); - _4YR50(maxInd2); - _4YR50.clear(); - for (int i=0; i5) _4YR50[i] = 0.97 + 0.0015*(i-5); - else if (i<90 && i>=45) _4YR50[i] = 1.03+0.0025*(i-45); - } - //printf("4YR %1.2f %1.2f\n",_4YR50[44],_4YR50[85] ); - _4YR60(maxInd); - _4YR60.clear(); - for (int i=0; i5) _4YR60[i] = 0.99 + 0.00125*(i-5); - else if (i<85 && i>=45) _4YR60[i] = 1.04+0.002*(i-45); - else if (i<140 && i >=85) _4YR60[i] = 1.12+0.003*(i-85); - } - //printf("4YR %1.2f %1.2f %1.2f\n",_4YR60[44],_4YR60[84],_4YR60[125] ); - _4YR70(maxInd); - _4YR70.clear(); - for (int i=0; i5) _4YR70[i] = 1.02 + 0.00075*(i-5); - else if (i<85 && i>=45) _4YR70[i] = 1.05+0.00175*(i-45); - else if (i<140 && i >=85) _4YR70[i] = 1.12+0.002*(i-85); - } - //printf("4YR %1.2f %1.2f %1.2f\n",_4YR70[44],_4YR70[84],_4YR70[125] ); - _4YR80(maxInd3); - _4YR80.clear(); - for (int i=0; i5) _4YR80[i] = 1.09 - 0.0002*(i-5); - } - //printf("4YR %1.2f \n",_4YR80[41] ); - - _25YR30(maxInd2); - _25YR30.clear(); - for (int i=0; i5) _25YR30[i] = 0.77 + 0.004*(i-5); - else if (i<90 && i>=45) _25YR30[i] = 0.94+0.004*(i-45); - } - //printf("25YR %1.2f %1.2f\n",_25YR30[44],_25YR30[74] ); - _25YR40(maxInd2); - _25YR40.clear(); - for (int i=0; i5) _25YR40[i] = 0.82 + 0.003*(i-5); - else if (i<90 && i>=45) _25YR40[i] = 0.94+0.002*(i-45); - } - //printf("25YR %1.2f %1.2f\n",_25YR40[44],_25YR40[84] ); - _25YR50(maxInd2); - _25YR50.clear(); - for (int i=0; i5) _25YR50[i] = 0.87+ 0.002*(i-5); - else if (i<90 && i>=45) _25YR50[i] = 0.95+0.003*(i-45); - } - //printf("25YR %1.2f %1.2f\n",_25YR50[44],_25YR50[84] ); - _25YR60(maxInd2); - _25YR60.clear(); - for (int i=0; i5) _25YR60[i] = 0.89+ 0.0015*(i-5); - else if (i<90 && i>=45) _25YR60[i] = 0.95+0.004*(i-45); - } - //printf("25YR %1.2f %1.2f\n",_25YR60[44],_25YR60[84] ); - _25YR70(maxInd2); - _25YR70.clear(); - for (int i=0; i5) _25YR70[i] = 0.92+ 0.001*(i-5); - else if (i<90 && i>=45) _25YR70[i] = 0.96+0.003*(i-45); - } - //printf("25YR %1.2f %1.2f\n",_25YR70[44],_25YR70[84] ); - - _10R30(maxInd2); - _10R30.clear(); - for (int i=0; i5) _10R30[i] = 0.62 + 0.00225*(i-5); - else if (i<90 && i>=45) _10R30[i] = 0.71+0.003*(i-45); - } - //printf("10R %1.2f %1.2f\n",_10R30[44],_10R30[84] ); - _10R40(maxInd2); - _10R40.clear(); - for (int i=0; i5) _10R40[i] = 0.66 + 0.0025*(i-5); - else if (i<90 && i>=45) _10R40[i] = 0.76+0.0035*(i-45); - } - //printf("10R %1.2f %1.2f\n",_10R40[44],_10R40[84] ); - _10R50(maxInd2); - _10R50.clear(); - for (int i=0; i5) _10R50[i] = 0.71 + 0.002*(i-5); - else if (i<90 && i>=45) _10R50[i] = 0.79+0.0043*(i-45); - } - //printf("10R %1.2f %1.2f\n",_10R50[44],_10R50[84] ); - _10R60(maxInd); - _10R60.clear(); - for (int i=0; i5) _10R60[i] = 0.73 + 0.00175*(i-5); - else if (i<85 && i>=45) _10R60[i] = 0.80 +0.0033*(i-45); - else if (i<140 && i >=85) _10R60[i] = 0.93+0.0018*(i-85); - } - //printf("10R %1.2f %1.2f %1.2f\n",_10R60[44],_10R60[84],_10R60[125] ); - _10R70(maxInd); - _10R70.clear(); - for (int i=0; i5) _10R70[i] = 0.75 + 0.0015*(i-5); - else if (i<85 && i>=45) _10R70[i] = 0.81 +0.0017*(i-45); - else if (i<140 && i >=85) _10R70[i] = 0.88+0.0025*(i-85); - } - //printf("10R %1.2f %1.2f %1.2f\n",_10R70[44],_10R70[84],_10R70[125] ); - - _9R30(maxInd2); - _9R30.clear(); - for (int i=0; i5) _9R30[i] = 0.57 + 0.002*(i-5); - else if (i<90 && i>=45) _9R30[i] = 0.65+0.0018*(i-45); - } - //printf("9R %1.2f %1.2f\n",_9R30[44],_9R30[84] ); - _9R40(maxInd2); - _9R40.clear(); - for (int i=0; i5) _9R40[i] = 0.61 + 0.002*(i-5); - else if (i<90 && i>=45) _9R40[i] = 0.69+0.0025*(i-45); - } - //printf("9R %1.2f %1.2f\n",_9R40[44],_9R40[84] ); - _9R50(maxInd); - _9R50.clear(); - for (int i=0; i5) _9R50[i] = 0.66 + 0.00175*(i-5); - else if (i<85 && i>=45) _9R50[i] = 0.73 +0.0025*(i-45); - else if (i<140 && i >=85) _9R50[i] = 0.83+0.0035*(i-85); - } - //printf("9R %1.2f %1.2f %1.2f\n",_9R50[44],_9R50[84],_9R50[125] ); - _9R60(maxInd); - _9R60.clear(); - for (int i=0; i5) _9R60[i] = 0.68 + 0.0015*(i-5); - else if (i<85 && i>=45) _9R60[i] = 0.74 +0.0022*(i-45); - else if (i<140 && i >=85) _9R60[i] = 0.93+0.0022*(i-85); - } - //printf("9R %1.2f %1.2f %1.2f\n",_9R60[44],_9R60[84],_9R60[125] ); - _9R70(maxInd2); - _9R70.clear(); - for (int i=0; i5) _9R70[i] = 0.70 + 0.0012*(i-5); - else if (i<90 && i>=45) _9R70[i] = 0.75+0.0013*(i-45); - } - //printf("9R %1.2f %1.2f\n",_9R70[44],_9R70[84] ); - - _7R30(maxInd2); - _7R30.clear(); - for (int i=0; i5) _7R30[i] = 0.48 + 0.0015*(i-5); - else if (i<90 && i>=45) _7R30[i] = 0.54-0.0005*(i-45); - } - //printf("7R %1.2f %1.2f\n",_7R30[44],_7R30[84] ); - _7R40(maxInd2); - _7R40.clear(); - for (int i=0; i5) _7R40[i] = 0.51 + 0.0015*(i-5); - else if (i<90 && i>=45) _7R40[i] = 0.57+0.0005*(i-45); - } - //printf("7R %1.2f %1.2f\n",_7R40[44],_7R40[84] ); - _7R50(maxInd); - _7R50.clear(); - for (int i=0; i5) _7R50[i] = 0.54 + 0.0015*(i-5); - else if (i<85 && i>=45) _7R50[i] = 0.60 +0.0005*(i-45); - else if (i<140 && i >=85) _7R50[i] = 0.62+0.0025*(i-85); - } - //printf("7R %1.2f %1.2f %1.2f\n",_7R50[44],_7R50[84],_7R50[125] ); - _7R60(maxInd); - _7R60.clear(); - for (int i=0; i5) _7R60[i] = 0.58 + 0.00075*(i-5); - else if (i<85 && i>=45) _7R60[i] = 0.61 +0.00075*(i-45); - else if (i<140 && i >=85) _7R60[i] = 0.64+0.001*(i-85); - } - //printf("7R %1.2f %1.2f %1.2f\n",_7R60[44],_7R60[84],_7R60[107] ); - _7R70(maxInd2); - _7R70.clear(); - for (int i=0; i5) _7R70[i] = 0.59 + 0.00075*(i-5); - else if (i<90 && i>=45) _7R70[i] = 0.62+0.00075*(i-45); - } - //printf("7R %1.2f %1.2f\n",_7R70[44],_7R70[84] ); - - //5R 1 2 3 - - //5R - _5R10(maxInd2); - _5R10.clear(); - for (int i=0; i5) _5R10[i] = 0.10 - 0.0018*(i-5); - else if (i<90 && i>=45) _5R10[i] = 0.035-0.003*(i-45); - } - //printf("5R %1.2f %1.2f\n",_5R10[44],_5R10[51] ); - _5R20(maxInd2); - _5R20.clear(); - for (int i=0; i5) _5R20[i] = 0.26 - 0.00075*(i-5); - else if (i<90 && i>=45) _5R20[i] = 0.023-0.0002*(i-45); - } - //printf("5R %1.2f %1.2f\n",_5R20[44],_5R20[70] ); - _5R30(maxInd2); - _5R30.clear(); - for (int i=0; i5) _5R30[i] = 0.39 + 0.00075*(i-5); - else if (i<90 && i>=45) _5R30[i] = 0.42-0.0007*(i-45); - } - //printf("5R %1.2f %1.2f\n",_5R30[44],_5R30[85] ); - - //25R - _25R10(maxInd3); - _25R10.clear(); - for (int i=0; i5) _25R10[i] = -0.03 - 0.002*(i-5); - } - //printf("25R %1.2f \n",_25R10[44]); - _25R20(maxInd2); - _25R20.clear(); - for (int i=0; i5) _25R20[i] = 0.13 - 0.0012*(i-5); - else if (i<90 && i>=45) _25R20[i] = 0.08-0.002*(i-45); - } - //printf("25R %1.2f %1.2f\n",_25R20[44],_25R20[69] ); - //25R30: 0.28, 0.26, 0.22 - _25R30(maxInd2); - _25R30.clear(); - for (int i=0; i5) _25R30[i] = 0.28 - 0.0005*(i-5); - else if (i<90 && i>=45) _25R30[i] = 0.26-0.0009*(i-45); - } - //printf("25R %1.2f %1.2f\n",_25R30[44],_25R30[85] ); - - - _10RP10(maxInd3); - _10RP10.clear(); - for (int i=0; i5) _10RP10[i] = -0.16 - 0.0017*(i-5); - } - //printf("10RP %1.2f \n",_10RP10[44]); - _10RP20(maxInd2); - _10RP20.clear(); - for (int i=0; i5) _10RP20[i] = 0.0 - 0.0018*(i-5); - else if (i<90 && i>=45) _10RP20[i] = -0.07-0.0012*(i-45); - } - //printf("10RP %1.2f %1.2f\n",_10RP20[44],_10RP20[69] ); - _10RP30(maxInd2); - _10RP30.clear(); - for (int i=0; i5) _10RP30[i] = 0.15 - 0.001*(i-5); - else if (i<90 && i>=45) _10RP30[i] = 0.11-0.0012*(i-45); - } - //printf("10RP %1.2f %1.2f\n",_10RP30[44],_10RP30[85] ); - - //7G - _7G30(maxInd); - _7G30.clear(); - for (int i=0; i5) _7G30[i] = 2.90 + 0.0027*(i-5); - else if (i<85 && i>=45) _7G30[i] = 3.01+0.0005*(i-45); - else if (i<140 && i >=85) _7G30[i] = 3.03+0.00075*(i-85); - } - //printf("7G %1.2f %1.2f %1.2f\n",_7G30[44],_7G30[84],_7G30[125] ); - _7G40(maxInd); - _7G40.clear(); - for (int i=0; i5) _7G40[i] = 2.89 + 0.00125*(i-5); - else if (i<85 && i>=45) _7G40[i] = 2.94+0.0015*(i-45); - else if (i<140 && i >=85) _7G40[i] = 3.0+0.001*(i-85); - } - //printf("7G %1.2f %1.2f %1.2f\n",_7G40[44],_7G40[84],_7G40[125] ); - _7G50(maxInd); - _7G50.clear(); - for (int i=0; i5) _7G50[i] = 2.87 + 0.0015*(i-5); - else if (i<85 && i>=45) _7G50[i] = 2.93+0.00125*(i-45); - else if (i<140 && i >=85) _7G50[i] = 2.98+0.001*(i-85); - } - //printf("7G %1.2f %1.2f %1.2f\n",_7G50[44],_7G50[84],_7G50[125] ); - _7G60(maxInd); - _7G60.clear(); - for (int i=0; i5) _7G60[i] = 2.86 + 0.00125*(i-5); - else if (i<85 && i>=45) _7G60[i] = 2.91+0.00125*(i-45); - else if (i<140 && i >=85) _7G60[i] = 2.96+0.00075*(i-85); - } - //printf("7G %1.2f %1.2f %1.2f\n",_7G60[44],_7G60[84],_7G60[125] ); - _7G70(maxInd); - _7G70.clear(); - for (int i=0; i5) _7G70[i] = 2.85 + 0.001*(i-5); - else if (i<85 && i>=45) _7G70[i] = 2.89+0.00125*(i-45); - else if (i<140 && i >=85) _7G70[i] = 2.94+0.00075*(i-85); - } - //printf("7G %1.2f %1.2f %1.2f\n",_7G70[44],_7G70[84],_7G70[125] ); - _7G80(maxInd); - _7G80.clear(); - for (int i=0; i5) _7G80[i] = 2.84 + 0.001*(i-5); - else if (i<85 && i>=45) _7G80[i] = 2.88+0.001*(i-45); - else if (i<140 && i >=85) _7G80[i] = 2.92+0.001*(i-85); - } - //printf("7G %1.2f %1.2f %1.2f\n",_7G80[44],_7G80[84],_7G80[125] ); - - - //5G - _5G30(maxInd); - _5G30.clear(); - for (int i=0; i5) _5G30[i] = 2.82 + 0.00175*(i-5); - else if (i<85 && i>=45) _5G30[i] = 2.89+0.0018*(i-45); - else if (i<140 && i >=85) _5G30[i] = 2.96+0.0012*(i-85); - } - //printf("5G %1.2f %1.2f %1.2f\n",_5G30[44],_5G30[84],_5G30[125] ); - _5G40(maxInd); - _5G40.clear(); - for (int i=0; i5) _5G40[i] = 2.80 + 0.0015*(i-5); - else if (i<85 && i>=45) _5G40[i] = 2.86+0.00175*(i-45); - else if (i<140 && i >=85) _5G40[i] = 2.93+0.00125*(i-85); - } - //printf("5G %1.2f %1.2f %1.2f\n",_5G40[44],_5G40[84],_5G40[125] ); - _5G50(maxInd); - _5G50.clear(); - for (int i=0; i5) _5G50[i] = 2.79 + 0.001*(i-5); - else if (i<85 && i>=45) _5G50[i] = 2.84+0.0015*(i-45); - else if (i<140 && i >=85) _5G50[i] = 2.90+0.0015*(i-85); - } - //printf("5G %1.2f %1.2f %1.2f\n",_5G50[44],_5G50[84],_5G50[125] ); - _5G60(maxInd); - _5G60.clear(); - for (int i=0; i5) _5G60[i] = 2.78 + 0.001*(i-5); - else if (i<85 && i>=45) _5G60[i] = 2.82+0.00175*(i-45); - else if (i<140 && i >=85) _5G60[i] = 2.89+0.001*(i-85); - } - //printf("5G %1.2f %1.2f %1.2f\n",_5G60[44],_5G60[84],_5G60[125] ); - _5G70(maxInd); - _5G70.clear(); - for (int i=0; i5) _5G70[i] = 2.77 + 0.001*(i-5); - else if (i<85 && i>=45) _5G70[i] = 2.81+0.00125*(i-45); - else if (i<140 && i >=85) _5G70[i] = 2.86+0.00125*(i-85); - } - //printf("5G %1.2f %1.2f %1.2f\n",_5G70[44],_5G70[84],_5G70[125] ); - _5G80(maxInd); - _5G80.clear(); - for (int i=0; i5) _5G80[i] = 2.76 + 0.001*(i-5); - else if (i<85 && i>=45) _5G80[i] = 2.8+0.00125*(i-45); - else if (i<140 && i >=85) _5G80[i] = 2.85+0.00125*(i-85); - } - //printf("5G %1.2f %1.2f %1.2f\n",_5G80[44],_5G80[84],_5G80[125] ); - - //25G - _25G30(maxInd); - _25G30.clear(); - for (int i=0; i5) _25G30[i] = 2.68 + 0.0015*(i-5); - else if (i<85 && i>=45) _25G30[i] = 2.74+0.0018*(i-45); - else if (i<140 && i >=85) _25G30[i] = 2.81+0.002*(i-85); - } - //printf("25G %1.2f %1.2f %1.2f\n",_25G30[44],_25G30[84],_25G30[125] ); - _25G40(maxInd); - _25G40.clear(); - for (int i=0; i5) _25G40[i] = 2.68 + 0.00075*(i-5); - else if (i<85 && i>=45) _25G40[i] = 2.71+0.0015*(i-45); - else if (i<140 && i >=85) _25G40[i] = 2.77+0.00125*(i-85); - } - //printf("25G %1.2f %1.2f %1.2f\n",_25G40[44],_25G40[84],_25G40[125] ); - _25G50(maxInd); - _25G50.clear(); - for (int i=0; i5) _25G50[i] = 2.65 + 0.00075*(i-5); - else if (i<85 && i>=45) _25G50[i] = 2.68+0.00125*(i-45); - else if (i<140 && i >=85) _25G50[i] = 2.73+0.00125*(i-85); - } - //printf("25G %1.2f %1.2f %1.2f\n",_25G50[44],_25G50[84],_25G50[125] ); - _25G60(maxInd); - _25G60.clear(); - for (int i=0; i5) _25G60[i] = 2.64 + 0.0005*(i-5); - else if (i<85 && i>=45) _25G60[i] = 2.66+0.001*(i-45); - else if (i<140 && i >=85) _25G60[i] = 2.70+0.001*(i-85); - } - //printf("25G %1.2f %1.2f %1.2f\n",_25G60[44],_25G60[84],_25G60[125] ); - _25G70(maxInd); - _25G70.clear(); - for (int i=0; i5) _25G70[i] = 2.64 + 0.00*(i-5); - else if (i<85 && i>=45) _25G70[i] = 2.64+0.00075*(i-45); - else if (i<140 && i >=85) _25G70[i] = 2.67+0.001*(i-85); - } - //printf("25G %1.2f %1.2f %1.2f\n",_25G70[44],_25G70[84],_25G70[125] ); - _25G80(maxInd); - _25G80.clear(); - for (int i=0; i5) _25G80[i] = 2.63 + 0.00*(i-5); - else if (i<85 && i>=45) _25G80[i] = 2.63+0.0005*(i-45); - else if (i<140 && i >=85) _25G80[i] = 2.65+0.0005*(i-85); - } - //printf("25G %1.2f %1.2f %1.2f\n",_25G80[44],_25G80[84],_25G80[125] ); - - - //1G - _1G30(maxInd); - _1G30.clear(); - for (int i=0; i5) _1G30[i] = 2.58 + 0.00025*(i-5); - else if (i<85 && i>=45) _1G30[i] = 2.59+0.001*(i-45); - else if (i<140 && i >=85) _1G30[i] = 2.63+0.00125*(i-85); - } - //printf("1G %1.2f %1.2f %1.2f\n",_1G30[44],_1G30[84],_1G30[125] ); - _1G40(maxInd); - _1G40.clear(); - for (int i=0; i5) _1G40[i] = 2.56 - 0.00025*(i-5); - else if (i<85 && i>=45) _1G40[i] = 2.55+0.0005*(i-45); - else if (i<140 && i >=85) _1G40[i] = 2.57+0.0005*(i-85); - } - //printf("1G %1.2f %1.2f %1.2f\n",_1G40[44],_1G40[84],_1G40[125] ); - _1G50(maxInd); - _1G50.clear(); - for (int i=0; i5) _1G50[i] = 2.55 - 0.00025*(i-5); - else if (i<85 && i>=45) _1G50[i] = 2.54+0.00025*(i-45); - else if (i<140 && i >=85) _1G50[i] = 2.55+0.0005*(i-85); - } - //printf("1G %1.2f %1.2f %1.2f\n",_1G50[44],_1G50[84],_1G50[125] ); - _1G60(maxInd); - _1G60.clear(); - for (int i=0; i5) _1G60[i] = 2.54 - 0.0005*(i-5); - else if (i<85 && i>=45) _1G60[i] = 2.52+0.00025*(i-45); - else if (i<140 && i >=85) _1G60[i] = 2.53+0.00025*(i-85); - } - //printf("1G %1.2f %1.2f %1.2f\n",_1G60[44],_1G60[84],_1G60[125] ); - _1G70(maxInd); - _1G70.clear(); - for (int i=0; i5) _1G70[i] = 2.53 - 0.0005*(i-5); - else if (i<85 && i>=45) _1G70[i] = 2.51+0.0*(i-45); - else if (i<140 && i >=85) _1G70[i] = 2.51+0.00025*(i-85); - } - //printf("1G %1.2f %1.2f %1.2f\n",_1G70[44],_1G70[84],_1G70[125] ); - _1G80(maxInd); - _1G80.clear(); - for (int i=0; i5) _1G80[i] = 2.52 - 0.0005*(i-5); - else if (i<85 && i>=45) _1G80[i] = 2.50+0.00*(i-45); - else if (i<140 && i >=85) _1G80[i] = 2.50+0.00*(i-85); - } - //printf("1G %1.2f %1.2f %1.2f\n",_1G80[44],_1G80[84],_1G80[125] ); - - - //10GY - _10GY30(maxInd); - _10GY30.clear(); - for (int i=0; i5) _10GY30[i] = 2.52 - 0.001*(i-5); - else if (i<85 && i>=45) _10GY30[i] = 2.48-0.002*(i-45); - else if (i<140 && i >=85) _10GY30[i] = 2.40+0.0025*(i-85); - } - //printf("10GY %1.2f %1.2f %1.2f\n",_10GY30[44],_10GY30[84],_10GY30[125] ); - _10GY40(maxInd); - _10GY40.clear(); - for (int i=0; i5) _10GY40[i] = 2.48 - 0.0005*(i-5); - else if (i<85 && i>=45) _10GY40[i] = 2.46-0.0005*(i-45); - else if (i<140 && i >=85) _10GY40[i] = 2.44-0.0015*(i-85); - } - //printf("10GY %1.2f %1.2f %1.2f\n",_10GY40[44],_10GY40[84],_10GY40[125] ); - _10GY50(maxInd); - _10GY50.clear(); - for (int i=0; i5) _10GY50[i] = 2.48 - 0.00075*(i-5); - else if (i<85 && i>=45) _10GY50[i] = 2.45-0.00075*(i-45); - else if (i<140 && i >=85) _10GY50[i] = 2.42-0.00175*(i-85); - } - //printf("10GY %1.2f %1.2f %1.2f\n",_10GY50[44],_10GY50[84],_10GY50[125] ); - _10GY60(maxInd); - _10GY60.clear(); - for (int i=0; i5) _10GY60[i] = 2.47 - 0.00125*(i-5); - else if (i<85 && i>=45) _10GY60[i] = 2.42-0.00025*(i-45); - else if (i<140 && i >=85) _10GY60[i] = 2.41-0.0005*(i-85); - } - //printf("10GY %1.2f %1.2f %1.2f\n",_10GY60[44],_10GY60[84],_10GY60[125] ); - _10GY70(maxInd); - _10GY70.clear(); - for (int i=0; i5) _10GY70[i] = 2.46 - 0.001*(i-5); - else if (i<85 && i>=45) _10GY70[i] = 2.42+0.0*(i-45); - else if (i<140 && i >=85) _10GY70[i] = 2.42-0.001*(i-85); - } - //printf("10GY %1.2f %1.2f %1.2f\n",_10GY70[44],_10GY70[84],_10GY70[125] ); - _10GY80(maxInd); - _10GY80.clear(); - for (int i=0; i5) _10GY80[i] = 2.45 - 0.00075*(i-5); - else if (i<85 && i>=45) _10GY80[i] = 2.42 - 0.0005*(i-45); - else if (i<140 && i >=85) _10GY80[i] = 2.40-0.0005*(i-85); - } - //printf("10GY %1.2f %1.2f %1.2f\n",_10GY80[44],_10GY80[84],_10GY80[125] ); - - - //75GY - _75GY30(maxInd2); - _75GY30.clear(); - for (int i=0; i5) _75GY30[i] = 2.36 - 0.0025*(i-5); - else if (i<90 && i>=45) _75GY30[i] = 2.26-0.00175*(i-45); - } - //printf("75GY %1.2f %1.2f\n",_75GY30[44],_75GY30[84] ); - _75GY40(maxInd2); - _75GY40.clear(); - for (int i=0; i5) _75GY40[i] = 2.34 - 0.00175*(i-5); - else if (i<90 && i>=45) _75GY40[i] = 2.27-0.00225*(i-45); - } - //printf("75GY %1.2f %1.2f \n",_75GY40[44],_75GY40[84] ); - _75GY50(maxInd); - _75GY50.clear(); - for (int i=0; i5) _75GY50[i] = 2.32 - 0.0015*(i-5); - else if (i<85 && i>=45) _75GY50[i] = 2.26-0.00175*(i-45); - else if (i<140 && i >=85) _75GY50[i] = 2.19-0.00325*(i-85); - } - //printf("75GY %1.2f %1.2f %1.2f %1.2f\n",_75GY50[44],_75GY50[84],_75GY50[125],_75GY50[139] ); - _75GY60(maxInd); - _75GY60.clear(); - for (int i=0; i5) _75GY60[i] = 2.30 - 0.00125*(i-5); - else if (i<85 && i>=45) _75GY60[i] = 2.25-0.001*(i-45); - else if (i<140 && i >=85) _75GY60[i] = 2.21-0.0027*(i-85); - } - //printf("75GY %1.2f %1.2f %1.2f\n",_75GY60[44],_75GY60[84],_75GY60[125] ); - _75GY70(maxInd); - _75GY70.clear(); - for (int i=0; i5) _75GY70[i] = 2.29 - 0.00125*(i-5); - else if (i<85 && i>=45) _75GY70[i] = 2.24-0.0015*(i-45); - else if (i<140 && i >=85) _75GY70[i] = 2.18-0.00175*(i-85); - } - //printf("75GY %1.2f %1.2f %1.2f\n",_75GY70[44],_75GY70[84],_75GY70[125] ); - _75GY80(maxInd); - _75GY80.clear(); - for (int i=0; i5) _75GY80[i] = 2.27 - 0.001*(i-5); - else if (i<85 && i>=45) _75GY80[i] = 2.23 - 0.001*(i-45); - else if (i<140 && i >=85) _75GY80[i] = 2.19-0.00175*(i-85); - } - //printf("75GY %1.2f %1.2f %1.2f\n",_75GY80[44],_75GY80[84],_75GY80[125] ); - - - //55GY - _5GY30(maxInd2); - _5GY30.clear(); - for (int i=0; i5) _5GY30[i] = 2.16 - 0.002*(i-5); - else if (i<90 && i>=45) _5GY30[i] = 2.07-0.0025*(i-45); - } - //printf("5GY %1.2f %1.2f\n",_5GY30[44],_5GY30[84] ); - - //5GY4: 2.14,2.04, 1.96, 1.91 //95 - - _5GY40(maxInd2); - _5GY40.clear(); - for (int i=0; i5) _5GY40[i] = 2.14 - 0.0025*(i-5); - else if (i<90 && i>=45) _5GY40[i] = 2.04-0.003*(i-45); - } - //printf("5GY %1.2f %1.2f \n",_5GY40[44],_5GY40[84] ); - _5GY50(maxInd); - _5GY50.clear(); - for (int i=0; i5) _5GY50[i] = 2.13 - 0.00175*(i-5); - else if (i<85 && i>=45) _5GY50[i] = 2.06-0.002*(i-45); - else if (i<140 && i >=85) _5GY50[i] = 1.98-0.00225*(i-85); - } - //printf("5GY %1.2f %1.2f %1.2f\n",_5GY50[44],_5GY50[84],_5GY50[125] ); - _5GY60(maxInd); - _5GY60.clear(); - for (int i=0; i5) _5GY60[i] = 2.11 - 0.0015*(i-5); - else if (i<85 && i>=45) _5GY60[i] = 2.05-0.002*(i-45); - else if (i<140 && i >=85) _5GY60[i] = 1.97-0.00275*(i-85); - } - //printf("5GY %1.2f %1.2f %1.2f\n",_5GY60[44],_5GY60[84],_5GY60[125] ); - _5GY70(maxInd); - _5GY70.clear(); - for (int i=0; i5) _5GY70[i] = 2.09 - 0.001*(i-5); - else if (i<85 && i>=45) _5GY70[i] = 2.05-0.00175*(i-45); - else if (i<140 && i >=85) _5GY70[i] = 1.98-0.002*(i-85); - } - //printf("5GY %1.2f %1.2f %1.2f\n",_5GY70[44],_5GY70[84],_5GY70[125] ); - _5GY80(maxInd); - _5GY80.clear(); - for (int i=0; i5) _5GY80[i] = 2.07 - 0.001*(i-5); - else if (i<85 && i>=45) _5GY80[i] = 2.03 - 0.00075*(i-45); - else if (i<140 && i >=85) _5GY80[i] = 2.0-0.002*(i-85); - } - //printf("5GY %1.2f %1.2f %1.2f\n",_5GY80[44],_5GY80[84],_5GY80[125] ); - - #ifdef _DEBUG - t2e.set(); - if (settings->verbose) - printf("Lutf Munsell %d usec\n", t2e.etime(t1e)); - #endif - } - -} +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2004-2010 Gabor Horvath +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ + +#include "rtengine.h" +#include "color.h" +#include "iccmatrices.h" +#include "mytime.h" +#include "sleef.c" +#include "opthelper.h" + +using namespace std; + +namespace rtengine { + + extern const Settings* settings; + + cmsToneCurve* Color::linearGammaTRC; + LUTf Color::cachef; + LUTf Color::gamma2curve; + + LUTf Color::gammatab; + LUTf Color::igammatab_srgb; + LUTf Color::gammatab_srgb; + // LUTf Color::igammatab_709; +// LUTf Color::gammatab_709; + LUTf Color::igammatab_55; + LUTf Color::gammatab_55; + LUTf Color::igammatab_4; + LUTf Color::gammatab_4; + + LUTf Color::igammatab_26_11; + LUTf Color::gammatab_26_11; + LUTf Color::igammatab_24_17; + LUTf Color::gammatab_24_17a; + LUTf Color::gammatab_13_2; + + // Wikipedia sRGB: Unlike most other RGB color spaces, the sRGB gamma cannot be expressed as a single numerical value. + // The overall gamma is approximately 2.2, consisting of a linear (gamma 1.0) section near black, and a non-linear section elsewhere involving a 2.4 exponent + // and a gamma (slope of log output versus log input) changing from 1.0 through about 2.3. + const double Color::sRGBGamma = 2.2; + const double Color::sRGBGammaCurve = 2.4; + + const double Color::eps_max=580.40756; //(MAXVALF* 216.0f/24389.0); + const double Color::eps=216.0f/24389.0;//0.008856 + const double Color::kappa=24389.0/27.0;//903.29630; + + const float Color::D50x=0.9642f; //0.96422; + const float Color::D50z=0.8249f; //0.82521; + const double Color::u0=4.0*D50x/(D50x+15+3*D50z); + const double Color::v0=9.0/(D50x+15+3*D50z); + const double Color::epskap=8.0; + /* + * Munsell Lch correction + * Copyright (c) 2011 Jacques Desmis + */ + // Munsell Lch LUTf : 195 LUT + // about 70% data are corrected with significative corrections + // almost all data are taken for BG, YR, G excepted a few extreme values with a slight correction + // No LUTf for BG and Y : low corrections + // Only between 5B and 5PB for L > 40 : under very low corrections for L < 40 + + //give hue in function of L and C : Munsell correction + LUTf Color::_4P10, Color::_4P20, Color::_4P30, Color::_4P40, Color::_4P50, Color::_4P60; + LUTf Color::_1P10, Color::_1P20, Color::_1P30, Color::_1P40, Color::_1P50, Color::_1P60; + LUTf Color::_10PB10, Color::_10PB20, Color::_10PB30, Color::_10PB40, Color::_10PB50, Color::_10PB60; + LUTf Color::_9PB10, Color::_9PB20, Color::_9PB30, Color::_9PB40, Color::_9PB50, Color::_9PB60, Color::_9PB70, Color::_9PB80; + LUTf Color::_75PB10, Color::_75PB20, Color::_75PB30, Color::_75PB40, Color::_75PB50, Color::_75PB60, Color::_75PB70, Color::_75PB80; + LUTf Color::_6PB10, Color::_6PB20, Color::_6PB30, Color::_6PB40, Color::_6PB50, Color::_6PB60, Color::_6PB70, Color::_6PB80; + LUTf Color::_45PB10, Color::_45PB20, Color::_45PB30, Color::_45PB40, Color::_45PB50, Color::_45PB60, Color::_45PB70, Color::_45PB80; + LUTf Color::_3PB10, Color::_3PB20, Color::_3PB30, Color::_3PB40, Color::_3PB50, Color::_3PB60, Color::_3PB70, Color::_3PB80; + LUTf Color::_15PB10, Color::_15PB20, Color::_15PB30, Color::_15PB40, Color::_15PB50, Color::_15PB60, Color::_15PB70, Color::_15PB80; + LUTf Color::_05PB40, Color::_05PB50, Color::_05PB60, Color::_05PB70, Color::_05PB80; + LUTf Color::_10B40, Color::_10B50, Color::_10B60, Color::_10B70, Color::_10B80; + LUTf Color::_9B40, Color::_9B50, Color::_9B60, Color::_9B70, Color::_9B80; + LUTf Color::_7B40, Color::_7B50, Color::_7B60, Color::_7B70, Color::_7B80; + LUTf Color::_5B40, Color::_5B50, Color::_5B60, Color::_5B70, Color::_5B80; + LUTf Color::_10YR20, Color::_10YR30, Color::_10YR40, Color::_10YR50, Color::_10YR60, Color::_10YR70, Color::_10YR80, Color::_10YR90; + LUTf Color::_85YR20, Color::_85YR30, Color::_85YR40, Color::_85YR50, Color::_85YR60, Color::_85YR70, Color::_85YR80, Color::_85YR90; + LUTf Color::_7YR30, Color::_7YR40, Color::_7YR50, Color::_7YR60, Color::_7YR70, Color::_7YR80; + LUTf Color::_55YR30, Color::_55YR40, Color::_55YR50, Color::_55YR60, Color::_55YR70, Color::_55YR80, Color::_55YR90; + LUTf Color::_4YR30, Color::_4YR40, Color::_4YR50, Color::_4YR60, Color::_4YR70, Color::_4YR80; + LUTf Color::_25YR30, Color::_25YR40, Color::_25YR50, Color::_25YR60, Color::_25YR70; + LUTf Color::_10R30, Color::_10R40, Color::_10R50, Color::_10R60, Color::_10R70; + LUTf Color::_9R30, Color::_9R40, Color::_9R50, Color::_9R60, Color::_9R70; + LUTf Color::_7R30, Color::_7R40, Color::_7R50, Color::_7R60, Color::_7R70; + LUTf Color::_5R10, Color::_5R20, Color::_5R30; + LUTf Color::_25R10, Color::_25R20, Color::_25R30; + LUTf Color::_10RP10, Color::_10RP20, Color::_10RP30; + LUTf Color::_7G30, Color::_7G40, Color::_7G50, Color::_7G60, Color::_7G70, Color::_7G80; + LUTf Color::_5G30, Color::_5G40, Color::_5G50, Color::_5G60, Color::_5G70, Color::_5G80; + LUTf Color::_25G30, Color::_25G40, Color::_25G50, Color::_25G60, Color::_25G70, Color::_25G80; + LUTf Color::_1G30, Color::_1G40, Color::_1G50, Color::_1G60, Color::_1G70, Color::_1G80; + LUTf Color::_10GY30, Color::_10GY40, Color::_10GY50, Color::_10GY60, Color::_10GY70, Color::_10GY80; + LUTf Color::_75GY30, Color::_75GY40, Color::_75GY50, Color::_75GY60, Color::_75GY70, Color::_75GY80; + LUTf Color::_5GY30, Color::_5GY40, Color::_5GY50, Color::_5GY60, Color::_5GY70, Color::_5GY80; + +#ifdef _DEBUG + MunsellDebugInfo::MunsellDebugInfo() { + reinitValues(); + } + void MunsellDebugInfo::reinitValues() { + maxdhue[0]=maxdhue[1]=maxdhue[2]=maxdhue[3]=0.0f; + maxdhuelum[0]=maxdhuelum[1]=maxdhuelum[2]=maxdhuelum[3]=0.0f; + depass=depassLum=0; + } +#endif + + + void Color::init () { + + int maxindex = 65536; + cachef(maxindex,LUT_CLIP_BELOW); + + gamma2curve(maxindex,LUT_CLIP_BELOW|LUT_CLIP_ABOVE); + + for (int i=0; ieps_max) { + cachef[i] = 327.68*( exp(1.0/3.0 * log((double)i / MAXVALF) )); + } + else { + cachef[i] = 327.68*((kappa*i/MAXVALF+16.0)/116.0); + } + } + + for (int i=0; i-0.00001) { // no fabs, slow! + h = 0.f; + s = 0.f; + } + else { + double h_; + if (l_ <= 0.5) + s = float( (M-m) / (M+m) ); + else + s = float( (M-m) / (2.0-M-m) ); + + if ( var_R == M ) h_ = (var_G - var_B)/C; + else if ( var_G == M ) h_ = 2. + (var_B - var_R)/C; + else h_ = 4. + (var_R - var_G)/C; + h = float(h_ /= 6.0); + + if ( h < 0.f ) h += 1.f; + if ( h > 1.f ) h -= 1.f; + } + } + + double Color::hue2rgb(double p, double q, double t){ + if (t < 0.) t += 6.; + else if( t > 6.) t -= 6.; + + if (t < 1.) return p + (q - p) * t; + else if (t < 3.) return q; + else if (t < 4.) return p + (q - p) * (4. - t); + else return p; + } + + void Color::hsl2rgb (float h, float s, float l, float &r, float &g, float &b) { + + if (s == 0) + r = g = b = 65535.0f * l; // achromatic + else { + double m2; + double h_ = double(h); + double s_ = double(s); + double l_ = double(l); + + if (l <= 0.5f) + m2 = l_ * (1.0 + s_); + else { + m2 = l_ + s_ - l_ * s_; + } + + double m1 = 2.0 * l_ - m2; + + r = float(65535.0 * hue2rgb (m1, m2, h_ * 6.0 + 2.0)); + g = float(65535.0 * hue2rgb (m1, m2, h_ * 6.0)); + b = float(65535.0 * hue2rgb (m1, m2, h_ * 6.0 - 2.0)); + } + } + + void Color::hsl2rgb01 (float h, float s, float l, float &r, float &g, float &b) { + + if (s == 0) + r = g = b = l; // achromatic + else { + double m2; + double h_ = double(h); + double s_ = double(s); + double l_ = double(l); + + if (l <= 0.5f) + m2 = l_ * (1.0 + s_); + else { + m2 = l_ + s_ - l_ * s_; + } + + double m1 = 2.0 * l_ - m2; + + r = float(hue2rgb (m1, m2, h_ * 6.0 + 2.0)); + g = float(hue2rgb (m1, m2, h_ * 6.0)); + b = float(hue2rgb (m1, m2, h_ * 6.0 - 2.0)); + } + } + + void Color::rgb2hsv(float r, float g, float b, float &h, float &s, float &v) { + double var_R = r / 65535.0; + double var_G = g / 65535.0; + double var_B = b / 65535.0; + + double var_Min = min(var_R,var_G,var_B); + double var_Max = max(var_R,var_G,var_B); + double del_Max = var_Max - var_Min; + v = var_Max; + if (del_Max<0.00001 && del_Max>-0.00001) { // no fabs, slow! + h = 0; + s = 0; + } + else { + s = del_Max/var_Max; + + if ( var_R == var_Max ) h = (var_G - var_B)/del_Max; + else if ( var_G == var_Max ) h = 2.0 + (var_B - var_R)/del_Max; + else if ( var_B == var_Max ) h = 4.0 + (var_R - var_G)/del_Max; + h /= 6.0; + + if ( h < 0 ) h += 1; + if ( h > 1 ) h -= 1; + } + } + + void Color::hsv2rgb (float h, float s, float v, float &r, float &g, float &b) { + + float h1 = h*6.f; // sector 0 to 5 + int i = (int)h1; // floor() is very slow, and h1 is always >0 + float f = h1 - i; // fractional part of h + + float p = v * ( 1.f - s ); + float q = v * ( 1.f - s * f ); + float t = v * ( 1.f - s * ( 1.f - f ) ); + + float r1,g1,b1; + + if (i==1) {r1 = q; g1 = v; b1 = p;} + else if (i==2) {r1 = p; g1 = v; b1 = t;} + else if (i==3) {r1 = p; g1 = q; b1 = v;} + else if (i==4) {r1 = t; g1 = p; b1 = v;} + else if (i==5) {r1 = v; g1 = p; b1 = q;} + else /*i==(0|6)*/ {r1 = v; g1 = t; b1 = p;} + + r = ((r1)*65535.0f); + g = ((g1)*65535.0f); + b = ((b1)*65535.0f); + } + + // Function copied for speed concerns + // Not exactly the same as above ; this one return a result in the [0.0 ; 1.0] range + void Color::hsv2rgb01 (float h, float s, float v, float &r, float &g, float &b) { + float h1 = h*6; // sector 0 to 5 + int i = int(h1); + float f = h1 - i; // fractional part of h + + float p = v * ( 1 - s ); + float q = v * ( 1 - s * f ); + float t = v * ( 1 - s * ( 1 - f ) ); + + if (i==1) {r = q; g = v; b = p;} + else if (i==2) {r = p; g = v; b = t;} + else if (i==3) {r = p; g = q; b = v;} + else if (i==4) {r = t; g = p; b = v;} + else if (i==5) {r = v; g = p; b = q;} + else /*(i==0|6)*/ {r = v; g = t; b = p;} + } + + void Color::hsv2rgb (float h, float s, float v, int &r, int &g, int &b) { + + float h1 = h*6; // sector 0 to 5 + int i = floor( h1 ); + float f = h1 - i; // fractional part of h + + float p = v * ( 1 - s ); + float q = v * ( 1 - s * f ); + float t = v * ( 1 - s * ( 1 - f ) ); + + float r1,g1,b1; + + if (i==0) {r1 = v; g1 = t; b1 = p;} + else if (i==1) {r1 = q; g1 = v; b1 = p;} + else if (i==2) {r1 = p; g1 = v; b1 = t;} + else if (i==3) {r1 = p; g1 = q; b1 = v;} + else if (i==4) {r1 = t; g1 = p; b1 = v;} + else if (i==5) {r1 = v; g1 = p; b1 = q;} + + r = (int)( r1 * 65535); + g = (int)( g1 * 65535); + b = (int)( b1 * 65535); + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + void Color::xyz2srgb (float x, float y, float z, float &r, float &g, float &b) { + + //Transform to output color. Standard sRGB is D65, but internal representation is D50 + //Note that it is only at this point that we should have need of clipping color data + + /*float x65 = d65_d50[0][0]*x + d65_d50[0][1]*y + d65_d50[0][2]*z ; + float y65 = d65_d50[1][0]*x + d65_d50[1][1]*y + d65_d50[1][2]*z ; + float z65 = d65_d50[2][0]*x + d65_d50[2][1]*y + d65_d50[2][2]*z ; + + r = sRGB_xyz[0][0]*x65 + sRGB_xyz[0][1]*y65 + sRGB_xyz[0][2]*z65; + g = sRGB_xyz[1][0]*x65 + sRGB_xyz[1][1]*y65 + sRGB_xyz[1][2]*z65; + b = sRGB_xyz[2][0]*x65 + sRGB_xyz[2][1]*y65 + sRGB_xyz[2][2]*z65;*/ + + /*r = sRGBd65_xyz[0][0]*x + sRGBd65_xyz[0][1]*y + sRGBd65_xyz[0][2]*z ; + g = sRGBd65_xyz[1][0]*x + sRGBd65_xyz[1][1]*y + sRGBd65_xyz[1][2]*z ; + b = sRGBd65_xyz[2][0]*x + sRGBd65_xyz[2][1]*y + sRGBd65_xyz[2][2]*z ;*/ + + r = ((sRGB_xyz[0][0]*x + sRGB_xyz[0][1]*y + sRGB_xyz[0][2]*z)) ; + g = ((sRGB_xyz[1][0]*x + sRGB_xyz[1][1]*y + sRGB_xyz[1][2]*z)) ; + b = ((sRGB_xyz[2][0]*x + sRGB_xyz[2][1]*y + sRGB_xyz[2][2]*z)) ; + + } + void Color::xyz2Prophoto (float x, float y, float z, float &r, float &g, float &b) { + r = ((prophoto_xyz[0][0]*x + prophoto_xyz[0][1]*y + prophoto_xyz[0][2]*z)) ; + g = ((prophoto_xyz[1][0]*x + prophoto_xyz[1][1]*y + prophoto_xyz[1][2]*z)) ; + b = ((prophoto_xyz[2][0]*x + prophoto_xyz[2][1]*y + prophoto_xyz[2][2]*z)) ; + } + void Color::Prophotoxyz (float r, float g, float b, float &x, float &y, float &z) { + x = ((xyz_prophoto[0][0]*r + xyz_prophoto[0][1]*g + xyz_prophoto[0][2]*b)) ; + y = ((xyz_prophoto[1][0]*r + xyz_prophoto[1][1]*g + xyz_prophoto[1][2]*b)) ; + z = ((xyz_prophoto[2][0]*r + xyz_prophoto[2][1]*g + xyz_prophoto[2][2]*b)) ; + } + + void Color::rgbxyz (float r, float g, float b, float &x, float &y, float &z, const double xyz_rgb[3][3]) { + x = ((xyz_rgb[0][0]*r + xyz_rgb[0][1]*g + xyz_rgb[0][2]*b)) ; + y = ((xyz_rgb[1][0]*r + xyz_rgb[1][1]*g + xyz_rgb[1][2]*b)) ; + z = ((xyz_rgb[2][0]*r + xyz_rgb[2][1]*g + xyz_rgb[2][2]*b)) ; + } + + void Color::rgbxyz (float r, float g, float b, float &x, float &y, float &z, const float xyz_rgb[3][3]) { + x = ((xyz_rgb[0][0]*r + xyz_rgb[0][1]*g + xyz_rgb[0][2]*b)) ; + y = ((xyz_rgb[1][0]*r + xyz_rgb[1][1]*g + xyz_rgb[1][2]*b)) ; + z = ((xyz_rgb[2][0]*r + xyz_rgb[2][1]*g + xyz_rgb[2][2]*b)) ; + } + + void Color::xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const double rgb_xyz[3][3]) { + //Transform to output color. Standard sRGB is D65, but internal representation is D50 + //Note that it is only at this point that we should have need of clipping color data + + /*float x65 = d65_d50[0][0]*x + d65_d50[0][1]*y + d65_d50[0][2]*z ; + float y65 = d65_d50[1][0]*x + d65_d50[1][1]*y + d65_d50[1][2]*z ; + float z65 = d65_d50[2][0]*x + d65_d50[2][1]*y + d65_d50[2][2]*z ; + + r = sRGB_xyz[0][0]*x65 + sRGB_xyz[0][1]*y65 + sRGB_xyz[0][2]*z65; + g = sRGB_xyz[1][0]*x65 + sRGB_xyz[1][1]*y65 + sRGB_xyz[1][2]*z65; + b = sRGB_xyz[2][0]*x65 + sRGB_xyz[2][1]*y65 + sRGB_xyz[2][2]*z65;*/ + + /*r = sRGBd65_xyz[0][0]*x + sRGBd65_xyz[0][1]*y + sRGBd65_xyz[0][2]*z ; + g = sRGBd65_xyz[1][0]*x + sRGBd65_xyz[1][1]*y + sRGBd65_xyz[1][2]*z ; + b = sRGBd65_xyz[2][0]*x + sRGBd65_xyz[2][1]*y + sRGBd65_xyz[2][2]*z ;*/ + + r = ((rgb_xyz[0][0]*x + rgb_xyz[0][1]*y + rgb_xyz[0][2]*z)) ; + g = ((rgb_xyz[1][0]*x + rgb_xyz[1][1]*y + rgb_xyz[1][2]*z)) ; + b = ((rgb_xyz[2][0]*x + rgb_xyz[2][1]*y + rgb_xyz[2][2]*z)) ; + } + + // same for float + void Color::xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const float rgb_xyz[3][3]) { + r = ((rgb_xyz[0][0]*x + rgb_xyz[0][1]*y + rgb_xyz[0][2]*z)) ; + g = ((rgb_xyz[1][0]*x + rgb_xyz[1][1]*y + rgb_xyz[1][2]*z)) ; + b = ((rgb_xyz[2][0]*x + rgb_xyz[2][1]*y + rgb_xyz[2][2]*z)) ; + } + + void Color::trcGammaBW (float &r, float &g, float &b, float gammabwr, float gammabwg, float gammabwb) { + // correct gamma for black and white image : pseudo TRC curve of ICC profil + b/=65535.0f; + b= pow (max(b,0.0f), gammabwb); + b *=65535.0f; + r/=65535.0f; + r= pow (max(r,0.0f), gammabwr); + r *=65535.0f; + g/=65535.0f; + g= pow (max(g,0.0f), gammabwg); + g *=65535.0f; + } + + /** @brief Compute the B&W constants for the B&W processing and its tool's GUI + * + * @param setting BlackWhite::setting + * @param setting BlackWhite::filter + */ + void Color::computeBWMixerConstants (const Glib::ustring &setting, const Glib::ustring &filter, const Glib::ustring &algo, float &filcor, float &mixerRed, float &mixerGreen, + float &mixerBlue, float mixerOrange, float mixerYellow, float mixerCyan, float mixerPurple, float mixerMagenta, + bool autoc, bool complement, float &kcorec, double &rrm, double &ggm, double &bbm) + { + float somm; + float som = mixerRed+mixerGreen+mixerBlue; + // rM = mixerRed, gM = mixerGreen, bM = mixerBlue ! + //presets + if (setting=="RGB-Abs" || setting=="ROYGCBPM-Abs") + kcorec=som/100.f; + + if (!autoc) { + //if (setting=="RGB-Abs" || setting=="ROYGCBPM-Abs") {} //Keep the RGB mixer values as is! + //else if(setting=="RGB-Rel" || setting=="ROYGCBPM-Rel") {} //Keep the RGB mixer values as is! + if (setting=="NormalContrast") { mixerRed=43.f ; mixerGreen=33.f; mixerBlue=30.f; } + else if(setting=="Panchromatic") { mixerRed=33.3f; mixerGreen=33.3f; mixerBlue=33.3f; } + else if(setting=="HyperPanchromatic") { mixerRed=41.f ; mixerGreen=25.f; mixerBlue=34.f; } + else if(setting=="LowSensitivity") { mixerRed=27.f ; mixerGreen=27.f; mixerBlue=46.f; } + else if(setting=="HighSensitivity") { mixerRed=30.f ; mixerGreen=28.f; mixerBlue=42.f; } + else if(setting=="Orthochromatic") { mixerRed=0.f ; mixerGreen=42.f; mixerBlue=58.f; } + else if(setting=="HighContrast") { mixerRed=40.f ; mixerGreen=34.f; mixerBlue=60.f; } + else if(setting=="Luminance") { mixerRed=30.f ; mixerGreen=59.f; mixerBlue=11.f; } + else if(setting=="Landscape") { mixerRed=66.f ; mixerGreen=24.f; mixerBlue=10.f; } + else if(setting=="Portrait") { mixerRed=54.f ; mixerGreen=44.f; mixerBlue=12.f; } + else if(setting=="InfraRed") { mixerRed=-40.f; mixerGreen=200.f; mixerBlue=-17.f; } + } + + rrm=mixerRed; + ggm=mixerGreen; + bbm=mixerBlue; + + somm=mixerRed+mixerGreen+mixerBlue; + mixerRed=mixerRed/somm; mixerGreen=mixerGreen/somm; mixerBlue=mixerBlue/somm; + float koymcp=0.f; + + if(setting=="ROYGCBPM-Abs" || setting=="ROYGCBPM-Rel") { + float obM=0.f; + float ogM=0.f; + float orM=0.f; + + float ybM=0.f; + float yrM=0.f; + float ygM=0.f; + + float mgM=0.f; + float mrM=0.f; + float mbM=0.f; + + float pgM=0.f; + float prM=0.f; + float pbM=0.f; + + float crM=0.f; + float cgM=0.f; + float cbM=0.f; + //printf("mixred=%f\n",mixerRed); + + float fcompl = 1.f; + if(complement && algo=="SP") fcompl = 3.f;//special + else if(complement && algo=="LI") fcompl = 1.5f;//linear + // ponderate filters: report to R=G=B=33 + // I ponder RGB channel, not only orange or yellow or cyan, etc...it's my choice ! + if(mixerOrange != 33) { + if (algo=="SP") {//special + if (mixerOrange >= 33) orM = fcompl*(mixerOrange*0.67f - 22.11f)/100.f; else orM = fcompl*(-0.3f*mixerOrange +9.9f)/100.f; + if (mixerOrange >= 33) ogM = fcompl*(-0.164f*mixerOrange+5.412f)/100.f; else ogM = fcompl*(0.4f*mixerOrange-13.2f)/100.f; + } + else if (algo=="LI") {//linear + orM = fcompl*(mixerOrange - 33.f)/100.f; + ogM = fcompl*(0.5f*mixerOrange-16.5f)/100.f; + } + if(complement) obM =(-0.492f*mixerOrange+16.236f)/100.f; + mixerRed += orM; + mixerGreen += ogM; + mixerBlue += obM; + koymcp += (orM+ogM+obM); + // printf("mixred+ORange=%f\n",mixerRed); + + } + if(mixerYellow != 33) { + if (algo=="SP") yrM = fcompl*(-0.134f*mixerYellow+4.422f)/100.f;//22.4 + else if (algo=="LI")yrM = fcompl*(0.5f*mixerYellow-16.5f)/100.f;//22.4 + ygM = fcompl*(0.5f *mixerYellow-16.5f )/100.f; + if(complement) ybM =(-0.492f*mixerYellow+16.236f)/100.f; + mixerRed += yrM; + mixerGreen += ygM; + mixerBlue += ybM; + koymcp += (yrM+ygM+ybM); + } + if(mixerMagenta != 33) { + if (algo=="SP"){ + if(mixerMagenta >= 33) mrM = fcompl*( 0.67f *mixerMagenta-22.11f)/100.f; else mrM = fcompl*(-0.3f*mixerMagenta +9.9f)/100.f; + if(mixerMagenta >= 33) mbM = fcompl*(-0.164f*mixerMagenta+5.412f)/100.f; else mbM = fcompl*( 0.4f*mixerMagenta-13.2f)/100.f; + } + else if (algo=="LI"){ + mrM = fcompl*(mixerMagenta-33.f)/100.f; + mbM = fcompl*(0.5f*mixerMagenta-16.5f)/100.f; + } + if(complement) mgM =(-0.492f*mixerMagenta+16.236f)/100.f; + mixerRed += mrM; + mixerGreen += mgM; + mixerBlue += mbM; + koymcp += (mrM+mgM+mbM); + } + if(mixerPurple != 33) { + if (algo=="SP") prM = fcompl*(-0.134f*mixerPurple+4.422f)/100.f; + else if (algo=="LI")prM = fcompl*(0.5f*mixerPurple-16.5f)/100.f; + pbM = fcompl*(0.5f*mixerPurple-16.5f)/100.f; + if(complement) pgM = (-0.492f*mixerPurple+16.236f)/100.f; + mixerRed += prM; + mixerGreen += pgM; + mixerBlue += pbM; + koymcp += (prM+pgM+pbM); + } + if(mixerCyan != 33) { + if (algo=="SP")cgM = fcompl*(-0.134f*mixerCyan +4.422f)/100.f; + else if (algo=="LI")cgM = fcompl*(0.5f*mixerCyan -16.5f)/100.f; + cbM = fcompl*(0.5f*mixerCyan-16.5f)/100.f; + if(complement) crM = (-0.492f*mixerCyan+16.236f)/100.f; + mixerRed += crM; + mixerGreen += cgM; + mixerBlue += cbM; + koymcp += (crM+cgM+cbM); + } + } + if(setting=="ROYGCBPM-Abs") + kcorec = koymcp+som/100.f; + //Color filters + float filred,filgreen,filblue; + filred=1.f;filgreen=1.f;filblue=1.f;filcor=1.f; + if (filter=="None") {filred=1.f; filgreen=1.f; filblue=1.f; filcor=1.f;} + else if (filter=="Red") {filred=1.f; filgreen=0.05f;filblue=0.f; filcor=1.08f;} + else if (filter=="Orange") {filred=1.f; filgreen=0.6f; filblue=0.f; filcor=1.35f;} + else if (filter=="Yellow") {filred=1.f; filgreen=1.f; filblue=0.05f;filcor=1.23f;} + else if (filter=="YellowGreen") {filred=0.6f; filgreen=1.f; filblue=0.3f;filcor=1.32f;} + else if (filter=="Green") {filred=0.2f; filgreen=1.f; filblue=0.3f;filcor=1.41f;} + else if (filter=="Cyan") {filred=0.05f;filgreen=1.f; filblue=1.f; filcor=1.23f;} + else if (filter=="Blue") {filred=0.f; filgreen=0.05f;filblue=1.f; filcor=1.20f;} + else if (filter=="Purple") {filred=1.f; filgreen=0.05f;filblue=1.f; filcor=1.23f;} + mixerRed = mixerRed * filred; + mixerGreen = mixerGreen * filgreen; + mixerBlue = mixerBlue * filblue; + + mixerRed = filcor*mixerRed / (mixerRed + mixerGreen + mixerBlue); + mixerGreen = filcor*mixerGreen / (mixerRed + mixerGreen + mixerBlue); + mixerBlue = filcor*mixerBlue / (mixerRed + mixerGreen + mixerBlue); + + if(filter!="None") { + som = mixerRed+mixerGreen+mixerBlue; + if(setting=="RGB-Abs" || setting=="ROYGCBPM-Abs") kcorec = kcorec*som; + } + + } + + void Color::interpolateRGBColor (const float balance, const float r1, const float g1, const float b1, const float r2, const float g2, const float b2, int toDo, const double xyz_rgb[3][3], const double rgb_xyz[3][3], float &ro, float &go, float &bo) { + float X1, Y1, Z1, X2, Y2, Z2, X, Y, Z; + float L1, L2, a_1, b_1, a_2, b_2, a, b; + float c1, c2, h1, h2; + float RR,GG,BB; + float Lr; + + // converting color 1 to Lch + Color::rgbxyz(r1, g1, b1, X1, Y1, Z1, xyz_rgb); + Color::XYZ2Lab(X1, Y1, Z1, L1, a_1, b_1); + Color::Lab2Lch(a_1, b_1, c1, h1); + Lr=L1/327.68f;//for gamutlch + //gamut control on r1 g1 b1 + #ifndef NDEBUG + bool neg=false; + bool more_rgb=false; + + //gamut control : Lab values are in gamut + Color::gamutLchonly(h1,Lr,c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f, neg, more_rgb); + #else + Color::gamutLchonly(h1,Lr,c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f); + #endif + + L1=Lr*327.68f; + + // converting color 2 to Lch + Color::rgbxyz(r2, g2, b2, X2, Y2, Z2, xyz_rgb); + Color::XYZ2Lab(X2, Y2, Z2, L2, a_2, b_2); + Color::Lab2Lch(a_2, b_2, c2, h2); + + Lr=L2/327.68f;//for gamutlch + //gamut control on r2 g2 b2 + #ifndef NDEBUG + neg=false; + more_rgb=false; + //gamut control : Lab values are in gamut + Color::gamutLchonly(h2,Lr,c2, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f, neg, more_rgb); + #else + Color::gamutLchonly(h2,Lr,c2, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f); + #endif + L2=Lr*327.68f; + + // interpolating Lch values + if (toDo & CHANNEL_LIGHTNESS) { L1 = L1 + (L2-L1)*balance;if(L1<0.f) L1=0.f;}//do not allow negative L + if (toDo & CHANNEL_CHROMATICITY) {c1 = c1 + (c2-c1)*balance;if(c1<0.f) c1=0.f; if(c1>180.f) c1=180.f;}//limit C to reasonable value + if (toDo & CHANNEL_HUE) h1 = interpolatePolarHue_PI(h1, h2, balance); + + // here I have put gamut control with gamutlchonly on final process + Lr=L1/327.68f;//for gamutlch + #ifndef NDEBUG + neg=false; + more_rgb=false; + //gamut control : Lab values are in gamut + Color::gamutLchonly(h1,Lr,c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f, neg, more_rgb); + #else + //gamut control : Lab values are in gamut + Color::gamutLchonly(h1,Lr,c1, RR, GG, BB, xyz_rgb, false, 0.15f, 0.96f); + #endif + //convert CH ==> ab + L1=Lr*327.68f; + + // converting back to rgb + Color::Lch2Lab(c1, h1, a, b); + Color::Lab2XYZ(L1, a, b, X, Y, Z); + Color::xyz2rgb(X, Y, Z, ro, go, bo, rgb_xyz); + } + + + void Color::interpolateRGBColor (float realL, float iplow, float iphigh, int algm, const float balance, int twoc, int metchrom, + bool chr, bool lum, float chromat, float luma, const float r1, const float g1, const float b1, + const float xl, const float yl, const float zl, const float x2, const float y2, const float z2, + int toDo, const double xyz_rgb[3][3], const double rgb_xyz[3][3], float &ro, float &go, float &bo) + { + float X1, Y1, Z1, X2, Y2, Z2, X, Y, Z,XL,YL,ZL; + float L1, L2, LL, a_1, b_1, a_2, b_2, a, b,a_L,b_L; + float c1, c2, h1, h2,cL,hL; + float RR,GG,BB; + float Lr; + float slc=0.f; + float hh=0.f; + float ll=0.f; + float sh=0.f; + bool LCH=false; + + float ha,hb,hc,ba; + float c_1,h_1; + // converting color 1 to Lab (image) + Color::rgbxyz(r1, g1, b1, X1, Y1, Z1, xyz_rgb); + if(algm == 1) {//use H interpolate + Color::XYZ2Lab(X1, Y1, Z1, L1, a_1, b_1); + //Color::Lab2Lch(a_1, b_1, c_1, h_1) ; + } + // converting color l lab(low) first color + if(twoc==0) { // 2 colours + //Color::rgbxyz(rl, gl, bl, XL, YL, ZL, xyz_rgb); + XL=xl; + YL=yl; + ZL=zl; + if(algm <= 1) {//use H interpolate + Color::XYZ2Lab(XL, YL, ZL, LL, a_L, b_L); + } + } + + // converting color 2 to lab (universal or high) + X2=x2; + Y2=y2; + Z2=z2; + float c_2,h_2; + if(algm == 1 ) { + Color::XYZ2Lab(X2, Y2, Z2, L2, a_2, b_2); + //Color::Lab2Lch(a_2, b_2, c_2, h_2) ; + } + float bal,balH,cal,calH,calm; + bal=balH=balance; + cal=calH=calm=1.f-chromat; + float med=(iphigh+iplow)/2.f; + float medH=(iphigh+iplow)/2.f; + float medL=(iphigh+iplow)/2.f; + + med=1.f;medH=0.f;//new algo for 2 colors + float calan; + calan=chromat; + + float calby; + calby=luma; + + if(twoc==0) { // 2 colours + calan=chromat; + + //calculate new balance in function of (arbitrary) "med".. I hope no error !! + if (realL > iplow && realL<=med) bal = realL*balance/(iplow-med) - med*balance/(iplow-med); + else if (realL <= iplow) bal = realL*balance/iplow; + + if (realL > medH && realL <= iphigh) balH = realL*balance/(iphigh-medH) - medH*balance/(iphigh-medH); + else if (realL > iphigh) balH = realL*balance*(iphigh-1.f) - balance*(iphigh-1.f); + + //calculate new balance chroma + if (realL > iplow && realL<=med) cal = realL*calan/(iplow-med) - med*calan/(iplow-med); + else if (realL <= iplow) cal = realL*calan/iplow; + + if (realL > medH && realL <= iphigh) calH = realL*calan/(iphigh-medH) - medH*calan/(iphigh-medH); + else if (realL > iphigh) calH = realL*calan;//*(iphigh-1.f) - calan*(iphigh-1.f);//it is better without transition in highlight + } + + float hX=0.f; + float hLL,hH,ccL,ccH,llH,aaH,bbH; + + if(algm <=1){ + if(twoc==0 && metchrom==3) { // 2 colours only with special "ab" + if(algm==1) { + aaH=a_1 + (a_2-a_1)*calH;bbH=b_1 + (b_2-b_1)*calH;//pass to line after + a_1=aaH + (a_L-aaH)*cal*balance;b_1=bbH + (b_L-bbH)*cal*balance; + } + } + else if(twoc==1) { + if(metchrom==0) { + a_1=a_1 + (a_2-a_1)*balance; + b_1=b_1 + (b_2-b_1)*balance; + } + else if(metchrom==1){ + a_1=a_1 + (a_2-a_1)*calan*balance; + b_1=b_1 + (b_2-b_1)*calan*balance; + } + else if(metchrom==2) { + a_1=a_1 + (a_2-a_1)*calan*balance; + b_1=b_1 + (b_2-b_1)*calby*balance; + } + } + } + else + h1=hX; + + Color::Lab2XYZ(L1, a_1, b_1, X, Y, Z); + + Color::xyz2rgb(X, Y, Z, ro, go, bo, rgb_xyz);// ro go bo in gamut + } + + void Color::calcGamma (double pwr, double ts, int mode, int imax, double &gamma0, double &gamma1, double &gamma2, double &gamma3, double &gamma4, double &gamma5) { + //from Dcraw (D.Coffin) + int i; + double g[6], bnd[2]={0,0}; + + g[0] = pwr; + g[1] = ts; + g[2] = g[3] = g[4] = 0; + bnd[g[1] >= 1] = 1; + if (g[1] && (g[1]-1)*(g[0]-1) <= 0) { + for (i=0; i < 48; i++) { + g[2] = (bnd[0] + bnd[1])/2; + if (g[0]) + bnd[(pow(g[2]/g[1],-g[0]) - 1)/g[0] - 1/g[2] > -1] = g[2]; + else + bnd[g[2]/exp(1-1/g[2]) < g[1]] = g[2]; + } + g[3] = g[2] / g[1]; + if (g[0]) g[4] = g[2] * (1/g[0] - 1); + } + if (g[0]) + g[5] = 1 / (g[1]*SQR(g[3])/2 - g[4]*(1 - g[3]) + (1 - pow(g[3],1+g[0]))*(1 + g[4])/(1 + g[0])) - 1; + else + g[5] = 1 / (g[1]*SQR(g[3])/2 + 1 - g[2] - g[3] - g[2]*g[3]*(log(g[3]) - 1)) - 1; + if (!mode--) { + gamma0=g[0];gamma1=g[1];gamma2=g[2];gamma3=g[3];gamma4=g[4];gamma5=g[5]; + return; + } + } + + void Color::Lab2XYZ(float L, float a, float b, float &x, float &y, float &z) { + float LL=L/327.68f; + float aa=a/327.68f; + float bb=b/327.68f; + float fy = (0.00862069f * LL) + 0.137932f; // (L+16)/116 + float fx = (0.002f * aa) + fy; + float fz = fy - (0.005f * bb); + x = 65535.0f*f2xyz(fx)*D50x; + z = 65535.0f*f2xyz(fz)*D50z; + y=(LL>epskap) ? 65535.0f*fy*fy*fy : 65535.0f*LL/kappa; + } + +#ifdef __SSE2__ + void Color::Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat &z) { + vfloat c327d68 = F2V(327.68f); + L /= c327d68; + a /= c327d68; + b /= c327d68; + vfloat fy = F2V(0.00862069f) * L + F2V(0.137932f); + vfloat fx = F2V(0.002f) * a + fy; + vfloat fz = fy - (F2V(0.005f) * b); + vfloat c65535 = F2V(65535.f); + x = c65535*f2xyz(fx)*F2V(D50x); + z = c65535*f2xyz(fz)*F2V(D50z); + vfloat res1 = fy*fy*fy; + vfloat res2 = L / F2V(kappa); + y = vself(vmaskf_gt(L, F2V(epskap)), res1, res2); + y *= c65535; + } +#endif // __SSE2__ + + void Color::XYZ2Lab(float X, float Y, float Z, float &L, float &a, float &b) { + + float x = X/D50x; + float z = Z/D50z; + float y= Y; + float fx,fy,fz; + + fx = (x<=65535.0f ? cachef[x] : (327.68f*xcbrtf(x/MAXVALF))); + fy = (y<=65535.0f ? cachef[y] : (327.68f*xcbrtf(y/MAXVALF))); + fz = (z<=65535.0f ? cachef[z] : (327.68f*xcbrtf(z/MAXVALF))); + + L = (116.0f * fy - 5242.88f); //5242.88=16.0*327.68; + a = (500.0f * (fx - fy) ); + b = (200.0f * (fy - fz) ); + } + + void Color::Lab2Yuv(float L, float a, float b, float &Y, float &u, float &v) { + float fy = (0.00862069 * L/327.68) + 0.137932; // (L+16)/116 + float fx = (0.002 * a/327.68) + fy; + float fz = fy - (0.005 * b/327.68); + float LL=L/327.68; + + float X = 65535.0*f2xyz(fx)*D50x; + // Y = 65535.0*f2xyz(fy); + float Z = 65535.0*f2xyz(fz)*D50z; + Y=(LL/327.68f>epskap) ? 65535.0*fy*fy*fy : 65535.0*LL/kappa; + + u = 4.0*X/(X+15*Y+3*Z)-u0; + v = 9.0*Y/(X+15*Y+3*Z)-v0; + } + + void Color::Yuv2Lab(float Yin, float u, float v, float &L, float &a, float &b, double wp[3][3]) { + float u1 = u + u0; + float v1 = v + v0; + + float Y = Yin; + float X = (9*u1*Y)/(4*v1*D50x); + float Z = (12 - 3*u1 - 20*v1)*Y/(4*v1*D50z); + + gamutmap(X,Y,Z,wp); + + float fx = (X<=65535.0 ? cachef[X] : (327.68*exp(log(X/MAXVALF)/3.0 ))); + float fy = (Y<=65535.0 ? cachef[Y] : (327.68*exp(log(Y/MAXVALF)/3.0 ))); + float fz = (Z<=65535.0 ? cachef[Z] : (327.68*exp(log(Z/MAXVALF)/3.0 ))); + + L = (116.0 * fy - 5242.88); //5242.88=16.0*327.68; + a = (500.0 * (fx - fy) ); + b = (200.0 * (fy - fz) ); + } + + void Color::Lab2Lch(float a, float b, float &c, float &h) { + c = (sqrtf(a*a+b*b))/327.68f; + h = xatan2f(b, a); + } + + void Color::Lch2Lab(float c, float h, float &a, float &b) { + float2 sincosval = xsincosf(h); + a = 327.68f * c * sincosval.y; + b = 327.68f * c * sincosval.x; + } + + void Color::Luv2Lch(float u, float v, float &c, float &h) { + c = sqrtf(u*u+v*v); + h = xatan2f(v, u); //WARNING: should we care of division by zero here? + if (h < 0.f) + h += 1.f; + } + + void Color::Lch2Luv(float c, float h, float &u, float &v) { + float2 sincosval = xsincosf(h); + u = c * sincosval.x; + v = c * sincosval.y; + } + + // NOT TESTED + void Color::XYZ2Luv (float X, float Y, float Z, float &L, float &u, float &v) { + + X /= 65535.f; + Y /= 65535.f; + Z /= 65535.f; + + if (Y > float(eps)) + L = 116.f * pow(Y, 1.f/3.f) -16.f; + else + L = float(kappa) * Y; + u = 13.f * L * float(u0); + v = 13.f * L * float(v0); + } + + // NOT TESTED + void Color::Luv2XYZ (float L, float u, float v, float &X, float &Y, float &Z) { + if (L > float(epskap)) { + float t = (L+16.f) / 116.f; + Y = t*t*t; + } + else + Y = L/float(kappa); + + float a = ((52.f*L) / (u+13.f*L*float(u0)) -1.f) / 3.f; + float d = Y * (((39*L) / (v+13*float(v0))) -5.f); + float b = -5.f*Y; + X = (d-b) / (a+1.f/3.f); + + Z = X*a+b; + + X *= 65535.f; + Y *= 65535.f; + Z *= 65535.f; + } + + /* + * Gamut mapping algorithm + * Copyright (c) 2010-2011 Emil Martinec + * + * Solutions to scaling u and v to XYZ paralleliped boundaries + * Some equations: + * + * fu(X,Y,Z) = 4 X/(X + 15 Y + 3 Z); + * fv(X,Y,Z) = 9 Y/(X + 15 Y + 3 Z); + * + * take the plane spanned by X=a*Xr+b*Xg+c*Xb etc with one of a,b,c equal to 0 or 1, + * and itersect with the line u0+lam*u, or in other words solve + * + * u0+lam*u=fu(X,Y,Z) + * v0+lam*v=fv(X,Y,Z) + * + * The value of lam is the scale factor that takes the color to the gamut boundary + * columns of the matrix p=xyz_rgb are RGB tristimulus primaries in XYZ + * c is the color fixed on the boundary; and m=0 for c=0, m=1 for c=255 + */ + void Color::gamutmap(float &X, float &Y, float &Z, const double p[3][3]) + { + float u = 4*X/(X+15*Y+3*Z)-u0; + float v = 9*Y/(X+15*Y+3*Z)-v0; + + float lam[3][2]; + float lam_min = 1.0; + + for (int c=0; c<3; c++) + for (int m=0; m<2; m++) { + + int c1=(c+1)%3; + int c2=(c+2)%3; + + lam[c][m] = (-(p[0][c1]*p[1][c]*((-12 + 3*u0 + 20*v0)*Y + 4*m*65535*v0*p[2][c2])) + + p[0][c]*p[1][c1]*((-12 + 3*u0 + 20*v0)*Y + 4*m*65535*v0*p[2][c2]) - + 4*v0*p[0][c1]*(Y - m*65535*p[1][c2])*p[2][c] + 4*v0*p[0][c]*(Y - m*65535*p[1][c2])*p[2][c1] - + (4*m*65535*v0*p[0][c2] - 9*u0*Y)*(p[1][c1]*p[2][c] - p[1][c]*p[2][c1])); + + lam[c][m] /= (3*u*Y*(p[0][c1]*p[1][c] - p[1][c1]*(p[0][c] + 3*p[2][c]) + 3*p[1][c]*p[2][c1]) + + 4*v*(p[0][c1]*(5*Y*p[1][c] + m*65535*p[1][c]*p[2][c2] + Y*p[2][c] - m*65535*p[1][c2]*p[2][c]) - + p[0][c]*(5*Y*p[1][c1] + m*65535*p[1][c1]*p[2][c2] + Y*p[2][c1] - m*65535*p[1][c2]*p[2][c1]) + + m*65535*p[0][c2]*(p[1][c1]*p[2][c] - p[1][c]*p[2][c1]))); + + if (lam[c][m]0) lam_min=lam[c][m]; + + } + + u = u*lam_min + u0; + v = v*lam_min + v0; + + X = (9*u*Y)/(4*v); + Z = (12 - 3*u - 20*v)*Y/(4*v); + } + + void Color::skinred ( double J, double h, double sres, double Sp, float dred, float protect_red, int sk, float rstprotection, float ko, double &s) + { + float factorskin, factorsat,factor, factorskinext, interm; + float scale = 100.0f/100.1f;//reduction in normal zone + float scaleext=1.0f;//reduction in transition zone + float protect_redh; + float deltaHH=0.3f;//HH value transition : I have choice 0.3 radians + float HH; + bool doskin=false; + //rough correspondence between h (JC) and H (lab) that has relatively little importance because transitions that blur the correspondence is not linear + if ((float)h>8.6f && (float)h<=74.f ) {HH=(1.15f/65.4f)*(float)h-0.0012f; doskin=true;}//H > 0.15 H<1.3 + else if((float)h>0.f && (float)h<=8.6f ) {HH=(0.19f/8.6f )*(float)h-0.04f; doskin=true;}//H>-0.04 H < 0.15 + else if((float)h>355.f && (float)h<=360.f) {HH=(0.11f/5.0f )*(float)h-7.96f; doskin=true;}//H>-0.15 <-0.04 + else if((float)h>74.f && (float)h<95.f ) {HH=(0.30f/21.0f)*(float)h+0.24285f; doskin=true;}//H>1.3 H<1.6 + + if(doskin) + { + float chromapro=sres/Sp; + if(sk==1){//in C mode to adapt dred to J + if (J<16.0) dred = 40.0f; + else if(J<22.0) dred = (4.1666f)*(float)J -26.6f; + else if(J<60.0) dred = 55.0f; + else if(J<70.0) dred = -1.5f*(float)J +145.0f; + else dred = 40.0f; + } + if(chromapro>0.0) Color::scalered ( rstprotection, chromapro, 0.0, HH, deltaHH, scale, scaleext);//Scale factor + if(chromapro>1.0) {interm=(chromapro-1.0f)*100.0f; + factorskin= 1.0f+(interm*scale)/100.0f; + factorskinext=1.0f+(interm*scaleext)/100.0f;} + else { + factorskin= chromapro ; + factorskinext= chromapro ; + } + factorsat=chromapro; + factor=factorsat; + Color::transitred ( HH, s, dred, factorskin, protect_red, factorskinext, deltaHH, factorsat, factor); //transition + s*=factor; + } + else s=ko*sres; + + } + void Color::skinredfloat ( float J, float h, float sres, float Sp, float dred, float protect_red, int sk, float rstprotection, float ko, float &s) + { + float HH; + bool doskin=false; + //rough correspondence between h (JC) and H (lab) that has relatively little importance because transitions that blur the correspondence is not linear + if ((float)h>8.6f && (float)h<=74.f ) {HH=(1.15f/65.4f)*(float)h-0.0012f; doskin=true;}//H > 0.15 H<1.3 + else if((float)h>0.f && (float)h<=8.6f ) {HH=(0.19f/8.6f )*(float)h-0.04f; doskin=true;}//H>-0.04 H < 0.15 + else if((float)h>355.f && (float)h<=360.f) {HH=(0.11f/5.0f )*(float)h-7.96f; doskin=true;}//H>-0.15 <-0.04 + else if((float)h>74.f && (float)h<95.f ) {HH=(0.30f/21.0f)*(float)h+0.24285f; doskin=true;}//H>1.3 H<1.6 + + if(doskin) + { + float factorskin, factorsat,factor, factorskinext; + float protect_redh; + float deltaHH=0.3f;//HH value transition : I have choice 0.3 radians + float chromapro=sres/Sp; + if(sk==1){//in C mode to adapt dred to J + if (J<16.0) dred = 40.0f; + else if(J<22.0) dred = (4.1666f)*(float)J -26.6f; + else if(J<60.0) dred = 55.0f; + else if(J<70.0) dred = -1.5f*(float)J +145.0f; + else dred = 40.0f; + } + if(chromapro>1.0) { + float scale = 0.999000999f; // 100.0f/100.1f; reduction in normal zone + float scaleext=1.0f;//reduction in transition zone + Color::scalered ( rstprotection, chromapro, 0.0, HH, deltaHH, scale, scaleext);//Scale factor + float interm=(chromapro-1.0f); + factorskin= 1.0f+(interm*scale); + factorskinext=1.0f+(interm*scaleext); + } + else { + factorskin= chromapro ; + factorskinext= chromapro ; + } + factorsat=chromapro; + factor=factorsat; + Color::transitred ( HH, s, dred, factorskin, protect_red, factorskinext, deltaHH, factorsat, factor); //transition + s*=factor; + } + else s=ko*sres; + + } + + + + + + + void Color::scalered ( const float rstprotection, const float param, const float limit, const float HH, const float deltaHH, float &scale, float &scaleext) + { + if(rstprotection<99.9999f) { + if(param > limit) + scale = rstprotection/100.1f; + if((HH< (1.3f+deltaHH) && HH >=1.3f)) + // scaleext=HH*(1.0f-scale)/deltaHH + 1.0f - (1.3f+deltaHH)*(1.0f-scale)/deltaHH; //transition for Hue (red - yellow) + // optimized formula + scaleext=(HH*(1.0f-scale) + deltaHH - (1.3f+deltaHH)*(1.0f-scale))/deltaHH; //transition for Hue (red - yellow) + else if((HH< 0.15f && HH >(0.15f-deltaHH))) + // scaleext=HH*(scale-1.0f)/deltaHH + 1.0f - (0.15f-deltaHH)*(scale-1.0f)/deltaHH; //transition for hue (red purple) + // optimized formula + scaleext=(HH*(scale-1.0f) + deltaHH - (0.15f-deltaHH)*(scale-1.0f))/deltaHH; //transition for hue (red purple) + } + } + + void Color::transitred (const float HH, float const Chprov1, const float dred, const float factorskin, const float protect_red, const float factorskinext, const float deltaHH, const float factorsat, float &factor) + { + if(HH>=0.15f && HH<1.3f) { + if (Chprov1(0.15f-deltaHH) || HH<(1.3f+deltaHH) ) { + if (Chprov1 < dred) + factor = factorskinext;// C=dred=55 => real max of skin tones + else if (Chprov1 < (dred+protect_red))// transition + // factor = (factorsat-factorskinext)/protect_red*Chprov1+factorsat-(dred+protect_red)*(factorsat-factorskinext)/protect_red; + // optimized formula + factor = ((factorsat-factorskinext)*Chprov1 + factorsat*protect_red - (dred+protect_red)*(factorsat-factorskinext))/protect_red; + } + } + + /* + * AllMunsellLch correction + * Copyright (c) 2012 Jacques Desmis + * + * This function corrects the color (hue) for changes in chromaticity and luminance + * to use in a "for" or "do while" statement + * + * Parameters: + * bool lumaMuns : true => luminance correction (for delta L > 10) and chroma correction ; false : only chroma + * float Lprov1 , Loldd : luminance after and before + * float HH: hue before + * float Chprov1, CC : chroma after and before + * float coorectionHuechroma : correction Hue for chromaticity (saturation) + * float correctlum : correction Hue for luminance (brigtness, contrast,...) + * MunsellDebugInfo* munsDbgInfo: (Debug target only) object to collect information. + */ +#ifdef _DEBUG + void Color::AllMunsellLch(bool lumaMuns, float Lprov1,float Loldd,float HH,float Chprov1,float CC,float &correctionHuechroma,float &correctlum, MunsellDebugInfo* munsDbgInfo) +#else + void Color::AllMunsellLch(bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHuechroma, float &correctlum) +#endif + { + + bool contin1,contin2; + float correctionHue=0.0,correctionHueLum=0.0; + bool correctL; + if(CC >= 6.0 && CC < 140) { //if C > 140 we say C=140 (only in Prophoto ...with very large saturation) + static const float huelimit[8]={-2.48,-0.55,0.44,1.52,1.87,3.09,-0.27,0.44};//limits hue of blue-purple, red-yellow, green-yellow, red-purple + if (Chprov1 > 140.f) + Chprov1=139.f; //limits of LUTf + if (Chprov1 < 6.f) + Chprov1=6.f; + for(int zo=1;zo<=4;zo++) { + if(HH>huelimit[2*zo-2] && HHmaxdhue[idx] = MAX(munsDbgInfo->maxdhue[idx], absCorrectionHue); +} + } + if(absCorrectionHue > 0.45) +#pragma omp atomic + munsDbgInfo->depass++; //verify if no bug in calculation +#endif + correctionHuechroma=correctionHue; //preserve + if(lumaMuns) { + float correctlumprov=0.f; + float correctlumprov2=0.f; + if(correctL) { + //for Munsell luminance correction + correctlumprov=correctionHueLum; + contin1=true; + correctL=false; + } + correctionHueLum=0.0; + correctionHue=0.0; + if(fabs(Lprov1-Loldd) > 6.0) { + // correction if delta L significative..Munsell luminance + MunsellLch (Loldd, HH,Chprov1, Chprov1, correctionHue, zo, correctionHueLum, correctL); + + if(correctL) { + correctlumprov2=correctionHueLum; + contin2=true; + correctL=false; + } + correctionHueLum=0.0; + + if(contin1==true && contin2==true) + correctlum=correctlumprov2-correctlumprov; +#ifdef _DEBUG + float absCorrectLum = fabs(correctlum); + if(correctlum !=0.0) { + int idx=zo-1; +#pragma omp critical (maxdhuelum) +{ + munsDbgInfo->maxdhuelum[idx] = MAX(munsDbgInfo->maxdhuelum[idx],absCorrectLum); +} + } + if(absCorrectLum > 0.35) +#pragma omp atomic + munsDbgInfo->depassLum++; //verify if no bug in calculation +#endif + } + } + } + } + + } + +#ifdef _DEBUG + if (correctlum < -0.35f) correctlum =-0.35f; + else if(correctlum > 0.35f) correctlum = 0.35f; + if (correctionHuechroma<-0.45f) correctionHuechroma=-0.45f; + else if(correctionHuechroma> 0.45f) correctionHuechroma= 0.45f; +#endif + + } + + /* + * GamutLchonly correction + * Copyright (c)2012 Jacques Desmis and Jean-Christophe Frisch + * + * This function puts the data (Lab) in the gamut of "working profile": + * it returns the corrected values of the chromaticity and luminance + * + * float HH : hue + * float Lprov1 : input luminance value, sent back corrected + * float Chprov1: input chroma value, sent back corrected + * float R,G,B : red, green and blue value of the corrected color + * double wip : working profile + * bool isHLEnabled : if "highlight reconstruction " is enabled + * float coef : a float number between [0.95 ; 1.0[... the nearest it is from 1.0, the more precise it will be... and the longer too as more iteration will be necessary) + * bool neg and moreRGB : only in DEBUG mode to calculate iterations for negatives values and > 65535 + */ +#ifdef _DEBUG + void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb) +#else + void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef) +#endif + { + const float ClipLevel = 65535.0f; + bool inGamut; +#ifdef _DEBUG + neg=false, more_rgb=false; +#endif + float2 sincosval = xsincosf(HH); + do { + inGamut=true; + + //Lprov1=LL; + float aprov1=Chprov1*sincosval.y; + float bprov1=Chprov1*sincosval.x; + + //conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction + float fy = (0.00862069f *Lprov1 )+ 0.137932f; + float fx = (0.002f * aprov1) + fy; + float fz = fy - (0.005f * bprov1); + + float x_ = 65535.0f * f2xyz(fx)*D50x; + // float y_ = 65535.0f * f2xyz(fy); + float z_ = 65535.0f * f2xyz(fz)*D50z; + float y_=(Lprov1>epskap) ? 65535.0*fy*fy*fy : 65535.0*Lprov1/kappa; + + xyz2rgb(x_,y_,z_,R,G,B,wip); + + // gamut control before saturation to put Lab values in future gamut, but not RGB + if (R<0.0f || G<0.0f || B<0.0f) { +#ifdef _DEBUG + neg=true; +#endif + if (Lprov1 < 0.1f) Lprov1 = 0.1f; + //gamut for L with ultra blue : we can improve the algorithm ... thinner, and other color ??? + if(HH < -0.9f && HH > -1.55f ) {//ultra blue + if(Chprov1 > 160.f) if (Lprov1 < 5.f) Lprov1 = 5.f;//very very very very high chroma + if(Chprov1 > 140.f) if (Lprov1 < 3.5f) Lprov1 = 3.5f; + if(Chprov1 > 120.f) if (Lprov1 < 2.f) Lprov1 = 2.f; + if(Chprov1 > 105.f) if (Lprov1 < 1.f) Lprov1 = 1.f; + if(Chprov1 > 90.f) if (Lprov1 < 0.7f) Lprov1 = 0.7f; + if(Chprov1 > 50.f) if (Lprov1 < 0.5f) Lprov1 = 0.5f; + if(Chprov1 > 20.f) if (Lprov1 < 0.4f) Lprov1 = 0.4f; + } + Chprov1 *= higherCoef; // decrease the chromaticity value + if (Chprov1 <= 3.0f) + Lprov1 += lowerCoef; + inGamut = false; + } else if (!isHLEnabled && (R>ClipLevel || G>ClipLevel || B>ClipLevel)) { + + // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut +#ifdef _DEBUG + more_rgb=true; +#endif + if (Lprov1 > 99.999f) + Lprov1 = 99.98f; + Chprov1 *= higherCoef; + if (Chprov1 <= 3.0f) + Lprov1 -= lowerCoef; + inGamut = false; + } + } + while (!inGamut); + //end first gamut control + } + + /* + * GamutLchonly correction + * Copyright (c)2012 Jacques Desmis and Jean-Christophe Frisch + * + * This function puts the data (Lab) in the gamut of "working profile": + * it returns the corrected values of the chromaticity and luminance + * + * float HH : hue + * float2 sincosval : sin and cos of HH + * float Lprov1 : input luminance value, sent back corrected + * float Chprov1: input chroma value, sent back corrected + * float R,G,B : red, green and blue value of the corrected color + * double wip : working profile + * bool isHLEnabled : if "highlight reconstruction " is enabled + * float coef : a float number between [0.95 ; 1.0[... the nearest it is from 1.0, the more precise it will be... and the longer too as more iteration will be necessary) + * bool neg and moreRGB : only in DEBUG mode to calculate iterations for negatives values and > 65535 + */ +#ifdef _DEBUG + void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb) +#else + void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef) +#endif + { + const float ClipLevel = 65535.0f; + bool inGamut; +#ifdef _DEBUG + neg=false, more_rgb=false; +#endif + do { + inGamut=true; + + //Lprov1=LL; + float aprov1=Chprov1*sincosval.y; + float bprov1=Chprov1*sincosval.x; + + //conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction + float fy = (0.00862069f *Lprov1 )+ 0.137932f; + float fx = (0.002f * aprov1) + fy; + float fz = fy - (0.005f * bprov1); + + float x_ = 65535.0f * f2xyz(fx)*D50x; + // float y_ = 65535.0f * f2xyz(fy); + float z_ = 65535.0f * f2xyz(fz)*D50z; + float y_=(Lprov1>epskap) ? 65535.0*fy*fy*fy : 65535.0*Lprov1/kappa; + + xyz2rgb(x_,y_,z_,R,G,B,wip); + + // gamut control before saturation to put Lab values in future gamut, but not RGB + if (R<0.0f || G<0.0f || B<0.0f) { +#ifdef _DEBUG + neg=true; +#endif + if (Lprov1 < 0.1f) Lprov1 = 0.1f; + //gamut for L with ultra blue : we can improve the algorithm ... thinner, and other color ??? + if(HH < -0.9f && HH > -1.55f ) {//ultra blue + if(Chprov1 > 160.f) if (Lprov1 < 5.f) Lprov1 = 5.f;//very very very very high chroma + if(Chprov1 > 140.f) if (Lprov1 < 3.5f) Lprov1 = 3.5f; + if(Chprov1 > 120.f) if (Lprov1 < 2.f) Lprov1 = 2.f; + if(Chprov1 > 105.f) if (Lprov1 < 1.f) Lprov1 = 1.f; + if(Chprov1 > 90.f) if (Lprov1 < 0.7f) Lprov1 = 0.7f; + if(Chprov1 > 50.f) if (Lprov1 < 0.5f) Lprov1 = 0.5f; + if(Chprov1 > 20.f) if (Lprov1 < 0.4f) Lprov1 = 0.4f; + } + Chprov1 *= higherCoef; // decrease the chromaticity value + if (Chprov1 <= 3.0f) + Lprov1 += lowerCoef; + inGamut = false; + } else if (!isHLEnabled && (R>ClipLevel || G>ClipLevel || B>ClipLevel)) { + + // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut +#ifdef _DEBUG + more_rgb=true; +#endif + if (Lprov1 > 99.999f) + Lprov1 = 99.98f; + Chprov1 *= higherCoef; + if (Chprov1 <= 3.0f) + Lprov1 -= lowerCoef; + inGamut = false; + } + } + while (!inGamut); + //end first gamut control + } + + +#ifdef _DEBUG + void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb) +#else + void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef) +#endif + { + const float ClipLevel = 65535.0f; + bool inGamut; +#ifdef _DEBUG + neg=false, more_rgb=false; +#endif + do { + inGamut=true; + + //Lprov1=LL; + float aprov1=Chprov1*sincosval.y; + float bprov1=Chprov1*sincosval.x; + + //conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction + float fy = (0.00862069f *Lprov1 )+ 0.137932f; + float fx = (0.002f * aprov1) + fy; + float fz = fy - (0.005f * bprov1); + + float x_ = 65535.0f * f2xyz(fx)*D50x; + // float y_ = 65535.0f * f2xyz(fy); + float z_ = 65535.0f * f2xyz(fz)*D50z; + float y_=(Lprov1>epskap) ? 65535.0*fy*fy*fy : 65535.0*Lprov1/kappa; + + float R,G,B; + xyz2rgb(x_,y_,z_,R,G,B,wip); + + // gamut control before saturation to put Lab values in future gamut, but not RGB + if (R<0.0f || G<0.0f || B<0.0f) { +#ifdef _DEBUG + neg=true; +#endif + if (Lprov1 < 0.01f) + Lprov1 = 0.01f; + Chprov1 *= higherCoef; // decrease the chromaticity value + if (Chprov1 <= 3.0f) + Lprov1 += lowerCoef; + inGamut = false; + } else if (!isHLEnabled && (R>ClipLevel || G>ClipLevel || B>ClipLevel)) { + + // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut +#ifdef _DEBUG + more_rgb=true; +#endif + if (Lprov1 > 99.999f) + Lprov1 = 99.98f; + Chprov1 *= higherCoef; + if (Chprov1 <= 3.0f) + Lprov1 -= lowerCoef; + inGamut = false; + } + } + while (!inGamut); + //end first gamut control + } + /* + * LabGamutMunsell + * Copyright (c) 2012 Jacques Desmis + * + * This function is the overall Munsell's corrections, but only on global statement: I think it's better to use local statement with AllMunsellLch + * not for use in a "for" or "do while" loop + * they are named accordingly : gamutLchonly and AllMunsellLch + * it can be used before and after treatment (saturation, gamma, luminance, ...) + * + * Parameters: + * float *labL : RT Lab L channel data + * float *laba : RT Lab a channel data + * float *labb : RT Lab b channel data + * bool corMunsell : performs Munsell correction + * bool lumaMuns : (used only if corMuns=true) + * true: apply luma + chroma Munsell correction if delta L > 10; + * false: only chroma correction only + * bool gamut : performs gamutLch + * const double wip[3][3]: matrix for working profile + * bool multiThread : parallelize the loop + */ +SSEFUNCTION void Color::LabGamutMunsell(float *labL, float *laba, float *labb, const int N, bool corMunsell, bool lumaMuns, bool isHLEnabled, bool gamut, const double wip[3][3], bool multiThread ) { +#ifdef _DEBUG + MyTime t1e,t2e; + t1e.set(); + int negat=0, moreRGB=0; + MunsellDebugInfo* MunsDebugInfo=NULL; + if (corMunsell) + MunsDebugInfo = new MunsellDebugInfo(); +#endif + float correctlum = 0.f; + float correctionHuechroma = 0.f; +#ifdef __SSE2__ + // precalculate H and C using SSE + float HHBuffer[N]; + float CCBuffer[N]; + __m128 c327d68v = _mm_set1_ps(327.68f); + __m128 av,bv; + int k; + for (k=0; kverbose) { + printf("Color::LabGamutMunsell (correction performed in %d usec):\n", t2e.etime(t1e)); + printf(" Gamut : G1negat=%iiter G165535=%iiter \n",negat,moreRGB); + if (MunsDebugInfo) { + printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); + printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhuelum[0] ,MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); + } + else { + printf(" Munsell correction wasn't requested\n"); + } + } + if (MunsDebugInfo) + delete MunsDebugInfo; +#endif + + } + + /* + * MunsellLch correction + * Copyright (c) 2012 Jacques Desmis + * + * Find the right LUT and calculate the correction + */ + void Color::MunsellLch (float lum, float hue, float chrom, float memChprov, float &correction, int zone, float &lbe, bool &correctL) { + + int x = int(memChprov); + int y = int(chrom); + + //begin PB correction + sky + if(zone==1) { + if(lum > 5.0) { + if(lum <15.0) { + if( (hue >= (_15PB10[x] - 0.035)) && (hue < (_15PB10[x] + 0.052) && x<=45)) {if(y>49) y=49;correction = _15PB10[y] - _15PB10[x] ;lbe=_15PB10[y];correctL=true;} + else if (( hue>=( _3PB10[x] -0.052)) && (hue < (_45PB10[x] + _3PB10[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB10[y] - _3PB10[x]; lbe =_3PB10[y];correctL=true;} + else if (( hue>=(_45PB10[x] + _3PB10[x])/2.0) && (hue < (_45PB10[x] +0.052)) && x <= 85) {if(y>89) y=89;correction = _45PB10[y] - _45PB10[x] ;lbe=_45PB10[y];correctL=true;} + else if (( hue>=(_6PB10[x] -0.052) && (hue < (_6PB10[x] + _75PB10[x])/2.0))) {correction = _6PB10[y] - _6PB10[x] ;lbe=_6PB10[y];correctL=true;} + else if (( hue>=(_6PB10[x] + _75PB10[x])/2.0) && (hue < (_9PB10[x] + _75PB10[x])/2.0)) {correction = _75PB10[y] - _75PB10[x] ;lbe=_75PB10[y];correctL=true;} + else if (( hue>=(_9PB10[x] + _75PB10[x])/2.0) && (hue < (_9PB10[x] + _10PB10[x])/2.0)) {correction = _9PB10[y] - _9PB10[x] ; lbe=_9PB10[y];correctL=true;} + else if (( hue>=(_10PB10[x] + _9PB10[x])/2.0) && (hue < (_1P10[x] + _10PB10[x])/2.0)) {correction = _10PB10[y] - _10PB10[x] ;lbe=_10PB10[y];correctL=true;} + else if (( hue>=(_10PB10[x] + _1P10[x])/2.0) && (hue < (_1P10[x] + _4P10[x])/2.0)) {correction = _1P10[y] - _1P10[x];lbe=_1P10[y];correctL=true;} + else if (( hue>=(_1P10[x] + _4P10[x])/2.0) && (hue < (0.035 + _4P10[x])/2.0)) {correction = _4P10[y] - _4P10[x] ;lbe=_4P10[y];correctL=true;} + } + else if (lum <25.0) { + if( (hue >= (_15PB20[x] - 0.035)) && (hue < (_15PB20[x] + _3PB20[x])/2.0) && x<=85) {if(y>89) y=89;correction = _15PB20[y] - _15PB20[x] ;lbe= _15PB20[y];correctL=true;} + else if (( hue>=(_15PB20[x] + _3PB20[x])/2.0) && (hue < (_45PB20[x] + _3PB20[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB20[y] - _3PB20[x] ;lbe= _3PB20[y];correctL=true;} + else if (( hue>=(_45PB20[x] + _3PB20[x])/2.0) && (hue < ( _45PB20[x] + 0.052)) && x <= 85) {if(y>89) y=89;correction = _45PB20[y] - _45PB20[x] ;lbe=_45PB20[y];correctL=true;} + else if (( hue>=(_45PB20[x] + 0.052)) && (hue < (_6PB20[x] + _75PB20[x])/2.0)) {correction = _6PB20[y] - _6PB20[x];lbe=_6PB20[y];correctL=true;} + else if (( hue>=(_6PB20[x] + _75PB20[x])/2.0) && (hue < (_9PB20[x] + _75PB20[x])/2.0)) {correction = _75PB20[y] - _75PB20[x] ;lbe=_75PB20[y];correctL=true;} + else if (( hue>=(_9PB20[x] + _75PB20[x])/2.0) && (hue < (_9PB20[x] + _10PB20[x])/2.0)) {correction = _9PB20[y] - _9PB20[x] ;lbe= _9PB20[y];correctL=true; } + else if (( hue>=(_10PB20[x] + _9PB20[x])/2.0) && (hue < (_1P20[x] + _10PB20[x])/2.0)) {correction = _10PB20[y] - _10PB20[x] ;lbe= _10PB20[y];correctL=true;} + else if (( hue>=(_10PB20[x] + _1P20[x])/2.0) && (hue < (_1P20[x] + _4P20[x])/2.0)) {correction = _1P20[y] - _1P20[x] ; lbe=_1P20[y];correctL=true;} + else if (( hue>=(_1P20[x] + _4P20[x])/2.0) && (hue < (0.035 + _4P20[x])/2.0)) {correction = _4P20[y] - _4P20[x] ; lbe=_4P20[y];correctL=true;} + } + else if (lum <35.0) { + if( (hue >= (_15PB30[x] - 0.035)) && (hue < (_15PB30[x] + _3PB30[x])/2.0) && x<=85 ) {if(y>89) y=89;correction = _15PB30[y] - _15PB30[x] ;lbe=_15PB30[y];correctL=true;} + else if (( hue>=(_15PB30[x] + _3PB30[x])/2.0) && (hue < (_45PB30[x] + _3PB30[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB30[y] - _3PB30[x] ;lbe=_3PB30[y];correctL=true;} + else if (( hue>=(_45PB30[x] + _3PB30[x])/2.0) && (hue < (_45PB30[x]+0.052)) && x <= 85) {if(y>89) y=89;correction = _45PB30[y] - _45PB30[x] ;lbe= _45PB30[y];correctL=true;} + else if (( hue>=( _45PB30[x]+ 0.052)) && (hue < (_6PB30[x] + _75PB30[x])/2.0)) {correction = _6PB30[y] - _6PB30[x] ; lbe=_6PB30[y];correctL=true;} + else if (( hue>=(_6PB30[x] + _75PB30[x])/2.0) && (hue < (_9PB30[x] + _75PB30[x])/2.0)) {correction = _75PB30[y] - _75PB30[x] ;lbe= _75PB30[y] ;correctL=true;} + else if (( hue>=(_9PB30[x] + _75PB30[x])/2.0) && (hue < (_9PB30[x] + _10PB30[x])/2.0)) {correction = _9PB30[y] - _9PB30[x] ;lbe=_9PB30[y]; correctL=true;} + else if (( hue>=(_10PB30[x] + _9PB30[x])/2.0) && (hue < (_1P30[x] + _10PB30[x])/2.0)) {correction = _10PB30[y] - _10PB30[x] ;lbe=_10PB30[y];correctL=true;} + else if (( hue>=(_10PB30[x] + _1P30[x])/2.0) && (hue < (_1P30[x] + _4P30[x])/2.0)) {correction = _1P30[y] - _1P30[x] ;lbe=_1P30[y];correctL=true; } + else if (( hue>=(_1P30[x] + _4P30[x])/2.0) && (hue < (0.035 + _4P30[x])/2.0)) {correction = _4P30[y] - _4P30[x] ;lbe=_4P30[y];correctL=true;} + } + else if (lum <45.0) { + if( (hue <= (_05PB40[x] + _15PB40[x])/2.0) && (hue > (_05PB40[x] + _10B40[x])/2.0) && x<75 ) {if(y>75) y=75; correction = _05PB40[y] - _05PB40[x] ;lbe=_05PB40[y];correctL=true;} + else if( (hue <= (_05PB40[x] + _10B40[x])/2.0) && (hue >(_10B40[x] + _9B40[x])/2.0) && x<70 ) {if(y>70) y=70;correction = _10B40[y] - _10B40[x] ;lbe=_10B40[y];correctL=true;} + else if( (hue <= (_10B40[x] + _9B40[x])/2.0) && (hue >(_9B40[x] + _7B40[x])/2.0) && x<70 ) {if(y>70) y=70;correction = _9B40[y] - _9B40[x] ;lbe=_9B40[y];correctL=true;} + else if( (hue <= (_9B40[x] + _7B40[x])/2.0) && (hue >(_5B40[x] + _7B40[x])/2.0) && x<70 ) {if(y>70) y=70;correction = _7B40[y] - _7B40[x] ;lbe= _7B40[y];correctL=true;} + else if (( hue<=(_5B40[x] + _7B40[x])/2.0) && (hue > (_5B40[x]-0.035)) && x < 70) {if(y>70) y=70; correction = _5B40[y] - _5B40[x] ;lbe= _5B40[y];correctL=true;} // + + else if( (hue >= (_15PB40[x] - 0.035)) && (hue < (_15PB40[x] + _3PB40[x])/2.0) && x<=85 ) {if(y>89) y=89;correction = _15PB40[y] - _15PB40[x] ; lbe= _15PB40[y];correctL=true;} + else if (( hue>=(_15PB40[x] + _3PB40[x])/2.0) && (hue < (_45PB40[x] + _3PB40[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB40[y] - _3PB40[x] ;lbe=_3PB40[y];correctL=true;} + else if (( hue>=(_45PB40[x] + _3PB40[x])/2.0) && (hue < (_45PB40[x]+0.052)) && x <= 85) {if(y>89) y=89;correction = _45PB40[y] - _45PB40[x] ;lbe=_45PB40[y] ;correctL=true;} + else if (( hue>=(_45PB40[x]+0.052)) && (hue < (_6PB40[x] + _75PB40[x])/2.0)) {correction = _6PB40[y] - _6PB40[x] ;lbe=_6PB40[y];correctL=true; } + else if (( hue>=(_6PB40[x] + _75PB40[x])/2.0) && (hue < (_9PB40[x] + _75PB40[x])/2.0)) {correction = _75PB40[y] - _75PB40[x] ; lbe=_75PB40[y];correctL=true;} + else if (( hue>=(_9PB40[x] + _75PB40[x])/2.0) && (hue < (_9PB40[x] + _10PB40[x])/2.0)) {correction = _9PB40[y] - _9PB40[x] ;lbe= _9PB40[y]; correctL=true;} + else if (( hue>=(_10PB40[x] + _9PB40[x])/2.0) && (hue < (_1P40[x] + _10PB40[x])/2.0)) {correction = _10PB40[y] - _10PB40[x] ;lbe=_10PB40[y];correctL=true;} + else if (( hue>=(_10PB40[x] + _1P40[x])/2.0) && (hue < (_1P40[x] + _4P40[x])/2.0)) {correction = _1P40[y] - _1P40[x] ;lbe=_1P40[y];correctL=true;} + else if (( hue>=(_1P40[x] + _4P40[x])/2.0) && (hue < (0.035 + _4P40[x])/2.0)) {correction = _4P40[y] - _4P40[x] ;lbe= _4P40[y];correctL=true;} + } + else if (lum <55.0) { + if( (hue <= (_05PB50[x] + _15PB50[x])/2.0) && (hue > (_05PB50[x] + _10B50[x])/2.0) && x<79 ) {if(y>79) y=79; correction = _05PB50[y] - _05PB50[x] ;lbe= _05PB50[y];correctL=true;} + else if( (hue <= (_05PB50[x] + _10B50[x])/2.0) && (hue >(_10B50[x] + _9B50[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _10B50[y] - _10B50[x] ;lbe=_10B50[y];correctL=true;} + else if( (hue <= (_10B50[x] + _9B50[x])/2.0) && (hue >(_9B50[x] + _7B50[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _9B50[y] - _9B50[x] ;lbe=_9B50[y];correctL=true;} + else if( (hue <= (_9B50[x] + _7B50[x])/2.0) && (hue >(_5B50[x] + _7B50[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _7B50[y] - _7B50[x] ;lbe=_7B50[y];correctL=true;} + else if (( hue<=(_5B50[x] + _7B50[x])/2.0) && (hue > (_5B50[x]-0.035)) && x < 79) {if(y>79) y=79; correction = _5B50[y] - _5B50[x] ;lbe=_5B50[y];correctL=true; } // + + else if( (hue >= (_15PB50[x] - 0.035)) && (hue < (_15PB50[x] + _3PB50[x])/2.0) && x<=85 ) {if(y>89) y=89;correction = _15PB50[y] - _15PB50[x] ; lbe= _15PB50[y];correctL=true;} + else if (( hue>=(_15PB50[x] + _3PB50[x])/2.0) && (hue < (_45PB50[x] + _3PB50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB50[y] - _3PB50[x] ;lbe=_3PB50[y];correctL=true;} + else if (( hue>=(_45PB50[x] + _3PB50[x])/2.0) && (hue < (_6PB50[x] + _45PB50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _45PB50[y] - _45PB50[x] ;lbe=_45PB50[y];correctL=true; } + else if (( hue>=(_6PB50[x] + _45PB50[x])/2.0) && (hue < (_6PB50[x] + _75PB50[x])/2.0) && x <=85) {if(y>89) y=89;correction = _6PB50[y] - _6PB50[x] ;lbe=_6PB50[y];correctL=true;} + else if (( hue>=(_6PB50[x] + _75PB50[x])/2.0) && (hue < (_9PB50[x] + _75PB50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _75PB50[y] - _75PB50[x] ;lbe=_75PB50[y];correctL=true;} + else if (( hue>=(_9PB50[x] + _75PB50[x])/2.0) && (hue < (_9PB50[x] + _10PB50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _9PB50[y] - _9PB50[x] ;lbe=_9PB50[y];correctL=true;} + else if (( hue>=(_10PB50[x] + _9PB50[x])/2.0) && (hue < (_1P50[x] + _10PB50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _10PB50[y] - _10PB50[x] ;lbe=_10PB50[y];correctL=true;} + else if (( hue>=(_10PB50[x] + _1P50[x])/2.0) && (hue < (_1P50[x] + _4P50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _1P50[y] - _1P50[x] ;lbe=_1P50[y];correctL=true; } + else if (( hue>=(_1P50[x] + _4P50[x])/2.0) && (hue < (0.035 + _4P50[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _4P50[y] - _4P50[x] ;lbe=_4P50[y];correctL=true;} + } + else if (lum <65.0) { + if( (hue <= (_05PB60[x] + _15PB60[x])/2.0) && (hue > (_05PB60[x] + _10B60[x])/2.0) && x<79 ) {if(y>79) y=79; correction = _05PB60[y] - _05PB60[x] ;lbe=_05PB60[y];correctL=true;} + else if( (hue <= (_05PB60[x] + _10B60[x])/2.0) && (hue >(_10B60[x] + _9B60[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _10B60[y] - _10B60[x] ;lbe= _10B60[y];correctL=true;} + else if( (hue <= (_10B60[x] + _9B60[x])/2.0) && (hue >(_9B60[x] + _7B60[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _9B60[y] - _9B60[x] ;lbe=_9B60[y];correctL=true;} + else if( (hue <= (_9B60[x] + _7B60[x])/2.0) && (hue >(_5B60[x] + _7B60[x])/2.0) && x<79 ) {if(y>79) y=79;correction = _7B60[y] - _7B60[x] ;lbe= _7B60[y];correctL=true;} + else if (( hue<=(_5B60[x] + _7B60[x])/2.0) && (hue > (_5B60[x]-0.035)) && x < 79) {if(y>79) y=79; correction = _5B60[y] - _5B60[x] ;lbe= _5B60[y];correctL=true;} // + + else if( (hue >= (_15PB60[x] - 0.035)) && (hue < (_15PB60[x] + _3PB60[x])/2.0) && x<=85 ) {if(y>89) y=89;correction = _15PB60[y] - _15PB60[x] ;lbe=_15PB60[y];correctL=true; } + else if (( hue>=(_15PB60[x] + _3PB60[x])/2.0) && (hue < (_45PB60[x] + _3PB60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _3PB60[y] - _3PB60[x] ;lbe=_3PB60[y];correctL=true;} + else if (( hue>=(_45PB60[x] + _3PB60[x])/2.0) && (hue < (_6PB60[x] + _45PB60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _45PB60[y] - _45PB60[x] ;lbe=_45PB60[y];correctL=true;} + else if (( hue>=(_6PB60[x] + _45PB60[x])/2.0) && (hue < (_6PB60[x] + _75PB60[x])/2.0) && x <=85) {if(y>89) y=89;correction = _6PB60[y] - _6PB60[x] ;lbe= _6PB60[y];correctL=true;} + else if (( hue>=(_6PB60[x] + _75PB60[x])/2.0) && (hue < (_9PB60[x] + _75PB60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _75PB60[y] - _75PB60[x] ;lbe= _75PB60[y];correctL=true;} + else if (( hue>=(_9PB60[x] + _75PB60[x])/2.0) && (hue < (_9PB60[x] + _10PB60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _9PB60[y] - _9PB60[x] ;lbe= _9PB60[y];correctL=true;} + else if (( hue>=(_10PB60[x] + _9PB60[x])/2.0) && (hue < (_1P60[x] + _10PB60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _10PB60[y] - _10PB60[x] ;lbe=_10PB60[y]; correctL=true;} + else if (( hue>=(_10PB60[x] + _1P60[x])/2.0) && (hue < (_1P60[x] + _4P60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _1P60[y] - _1P60[x] ; lbe= _1P60[y];correctL=true;} + else if (( hue>=(_1P60[x] + _4P60[x])/2.0) && (hue < (0.035 + _4P60[x])/2.0) && x <= 85) {if(y>89) y=89;correction = _4P60[y] - _4P60[x] ;lbe=_4P60[y];correctL=true; } + } + else if (lum < 75.0) { + if( (hue <= (_05PB70[x] + _15PB70[x])/2.0) && (hue > (_05PB70[x] + _10B70[x])/2.0) && x<50 ) {if(y>49) y=49; correction = _05PB70[y] - _05PB70[x] ;lbe=_05PB70[y];correctL=true;} + else if( (hue <= (_05PB70[x] + _10B70[x])/2.0) && (hue >(_10B70[x] + _9B70[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _10B70[y] - _10B70[x] ;lbe=_10B70[y];correctL=true;} + else if( (hue <= (_10B70[x] + _9B70[x])/2.0) && (hue >(_9B70[x] + _7B70[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _9B70[y] - _9B70[x] ;lbe= _9B70[y];correctL=true;} + else if( (hue <= (_9B70[x] + _7B70[x])/2.0) && (hue >(_5B70[x] + _7B70[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _7B70[y] - _7B70[x] ;lbe=_7B70[y];correctL=true;} + else if (( hue<=(_5B70[x] + _7B70[x])/2.0) && (hue > (_5B70[x]-0.035)) && x < 50) {if(y>49) y=49; correction = _5B70[y] - _5B70[x] ;lbe= _5B70[y];correctL=true;} // + + else if( (hue >= (_15PB70[x] - 0.035)) && (hue < (_15PB70[x] + _3PB70[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _15PB70[y] - _15PB70[x] ;lbe=_15PB70[y];correctL=true; } + else if (( hue>=(_45PB70[x] + _3PB70[x])/2.0) && (hue < (_6PB70[x] + _45PB70[x])/2.0) && x < 50) {if(y>49) y=49;correction = _45PB70[y] - _45PB70[x] ;lbe=_45PB70[y];correctL=true;} + else if (( hue>=(_6PB70[x] + _45PB70[x])/2.0) && (hue < (_6PB70[x] + _75PB70[x])/2.0) && x <50) {if(y>49) y=49;correction = _6PB70[y] - _6PB70[x] ;lbe=_6PB70[y];correctL=true;} + else if (( hue>=(_6PB70[x] + _75PB70[x])/2.0) && (hue < (_9PB70[x] + _75PB70[x])/2.0) && x <50) {if(y>49) y=49;correction = _75PB70[y] - _75PB70[x] ;lbe=_75PB70[y];correctL=true; } + else if (( hue>=(_9PB70[x] + _75PB70[x])/2.0) && (hue < (_9PB70[x] + 0.035)) && x <50) {if(y>49) y=49;correction = _9PB70[y] - _9PB70[x] ;lbe=_9PB70[y];correctL=true;} + } + else if (lum < 85.0) { + if( (hue <= (_05PB80[x] + _15PB80[x])/2.0) && (hue > (_05PB80[x] + _10B80[x])/2.0) && x<40 ) {if(y>39) y=39; correction = _05PB80[y] - _05PB80[x] ;lbe=_05PB80[y] ;correctL=true;} + else if( (hue <= (_05PB80[x] + _10B80[x])/2.0) && (hue >(_10B80[x] + _9B80[x])/2.0) && x<40 ) {if(y>39) y=39;correction = _10B80[y] - _10B80[x] ;lbe=_10B80[y];correctL=true;} + else if( (hue <= (_10B80[x] + _9B80[x])/2.0) && (hue >(_9B80[x] + _7B80[x])/2.0) && x<40 ) {if(y>39) y=39;correction = _9B80[y] - _9B80[x] ;lbe= _9B80[y];correctL=true;} + else if( (hue <= (_9B80[x] + _7B80[x])/2.0) && (hue >(_5B80[x] + _7B80[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _7B80[y] - _7B80[x] ;lbe=_7B80[y];correctL=true;} + else if (( hue<=(_5B80[x] + _7B80[x])/2.0) && (hue > (_5B80[x]-0.035)) && x < 50) {if(y>49) y=49; correction = _5B80[y] - _5B80[x] ; lbe=_5B80[y];correctL=true;} // + + else if( (hue >= (_15PB80[x] - 0.035)) && (hue < (_15PB80[x] + _3PB80[x])/2.0) && x<50 ) {if(y>49) y=49;correction = _15PB80[y] - _15PB80[x] ; lbe=_15PB80[y];correctL=true;} + else if (( hue>=(_45PB80[x] + _3PB80[x])/2.0) && (hue < (_6PB80[x] + _45PB80[x])/2.0) && x < 50) {if(y>49) y=49;correction = _45PB80[y] - _45PB80[x] ;lbe= _45PB80[y];correctL=true;} + else if (( hue>=(_6PB80[x] + _45PB80[x])/2.0) && (hue < (_6PB80[x] + _75PB80[x])/2.0) && x <50) {if(y>49) y=49;correction = _6PB80[y] - _6PB80[x] ;lbe=_6PB80[y];correctL=true;} + else if (( hue>=(_6PB80[x] + _75PB80[x])/2.0) && (hue < (_9PB80[x] + _75PB80[x])/2.0) && x <50) {if(y>49) y=49;correction = _75PB80[y] - _75PB80[x] ;lbe=_75PB80[y];correctL=true; } + else if (( hue>=(_9PB80[x] + _75PB80[x])/2.0) && (hue < (_9PB80[x] + 0.035)) && x <50) {if(y>49) y=49;correction = _9PB80[y] - _9PB80[x] ;lbe=_9PB80[y]; correctL=true;} + } + } + } + // end PB correction + + //red yellow correction + else if(zone==2) { + if(lum > 15.0) { + if(lum < 25.0) { + if( (hue <= (_10YR20[x] + 0.035)) && (hue > (_10YR20[x] + _85YR20[x])/2.0) && x<=45) {if(y>49) y=49;correction = _10YR20[y] - _10YR20[x] ;lbe=_10YR20[y];correctL=true;} + else if (( hue<=(_85YR20[x] + _10YR20[x])/2.0) && (hue > (_85YR20[x] + 0.035) && x <= 45)) {if(y>49) y=49;correction = _85YR20[y] - _85YR20[x] ;lbe= _85YR20[y];correctL=true;} + } + else if (lum <35.0) { + if( (hue <= (_10YR30[x] + 0.035)) && (hue > (_10YR30[x] + _85YR30[x])/2.0) && x < 85) {if(y>89) y=89;correction = _10YR30[y] - _10YR30[x] ;lbe=_10YR30[y];correctL=true;} + else if( (hue <= (_10YR30[x] + _85YR30[x])/2.0) && (hue >(_85YR30[x] + _7YR30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _85YR30[y] - _85YR30[x] ;lbe= _85YR30[y];correctL=true;} + else if (( hue<=(_85YR30[x] + _7YR30[x])/2.0) && (hue > (_7YR30[x] + _55YR30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _7YR30[y] - _7YR30[x] ;lbe=_7YR30[y];correctL=true;} + else if (( hue<=(_7YR30[x] + _55YR30[x])/2.0) && (hue > (_55YR30[x] + _4YR30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _55YR30[y] - _55YR30[x] ;lbe=_55YR30[y];correctL=true; } + else if (( hue<=(_55YR30[x] + _4YR30[x])/2.0) && (hue > (_4YR30[x] + _25YR30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _4YR30[y] - _4YR30[x] ;lbe= _4YR30[y];correctL=true;} + else if (( hue<=(_4YR30[x] + _25YR30[x])/2.0) && (hue > (_25YR30[x] + _10R30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _25YR30[y] - _25YR30[x] ;lbe=_25YR30[y];correctL=true;} + else if (( hue<=(_25YR30[x] + _10R30[x])/2.0) && (hue > (_10R30[x] + _9R30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10R30[y] - _10R30[x] ; lbe=_10R30[y];correctL=true;} + else if (( hue<=(_10R30[x] + _9R30[x])/2.0) && (hue > (_9R30[x] + _7R30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _9R30[y] - _9R30[x] ;lbe=_9R30[y];correctL=true;} + else if (( hue<=(_9R30[x] + _7R30[x])/2.0) && (hue > (_7R30[x] -0.035))&& x < 85) {if(y>89) y=89;correction = _7R30[y] - _7R30[x] ; lbe=_7R30[y] ;correctL=true;} + } + else if (lum <45.0) { + if( (hue <= (_10YR40[x] + 0.035)) && (hue > (_10YR40[x] + _85YR40[x])/2.0)&& x<85) {if(y>89) y=89;correction = _10YR40[y] - _10YR40[x] ;lbe=_10YR40[y];correctL=true;} + else if( (hue <= (_10YR40[x] + _85YR40[x])/2.0) && (hue >(_85YR40[x] + _7YR40[x])/2.0)&& x < 85 ) {if(y>89) y=89;correction = _85YR40[y] - _85YR40[x] ;lbe= _85YR40[y];correctL=true;} + else if (( hue<=(_85YR40[x] + _7YR40[x])/2.0) && (hue > (_7YR40[x] + _55YR40[x])/2.0) && x < 85) {if(y>89) y=89;correction = _7YR40[y] - _7YR40[x] ;lbe= _7YR40[y];correctL=true;} + else if (( hue<=(_7YR40[x] + _55YR40[x])/2.0) && (hue > (_55YR40[x] + _4YR40[x])/2.0)&& x < 85 ) {if(y>89) y=89;correction = _55YR40[y] - _55YR40[x] ;lbe=_55YR40[y];correctL=true; } + else if (( hue<=(_55YR40[x] + _4YR40[x])/2.0) && (hue > (_4YR40[x] + _25YR40[x])/2.0)&& x < 85 ) {if(y>89) y=89;correction = _4YR40[y] - _4YR40[x] ;lbe=_4YR40[y]; correctL=true;} + else if (( hue<=(_4YR40[x] + _25YR40[x])/2.0) && (hue > (_25YR40[x] + _10R40[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _25YR40[y] - _25YR40[x] ;lbe=_25YR40[y] ;correctL=true;} + else if (( hue<=(_25YR40[x] + _10R40[x])/2.0) && (hue > (_10R40[x] + _9R40[x])/2.0) && x < 85) {if(y>89) y=89;correction = _10R40[y] - _10R40[x] ; lbe=_10R40[y];correctL=true;} + else if (( hue<=(_10R40[x] + _9R40[x])/2.0) && (hue > (_9R40[x] + _7R40[x])/2.0)&& x < 85 ) {if(y>89) y=89;correction = _9R40[y] - _9R40[x] ;lbe=_9R40[y];correctL=true;} + else if (( hue<=(_9R40[x] + _7R40[x])/2.0) && (hue > (_7R40[x] -0.035))&& x < 85 ) {if(y>89) y=89;correction = _7R40[y] - _7R40[x] ; lbe=_7R40[y];correctL=true;} + } + else if (lum <55.0) { + if( (hue <= (_10YR50[x] + 0.035)) && (hue > (_10YR50[x] + _85YR50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10YR50[y] - _10YR50[x] ;lbe=_10YR50[y];correctL=true;} + else if( (hue <= (_10YR50[x] + _85YR50[x])/2.0) && (hue >(_85YR50[x] + _7YR50[x])/2.0)&& x < 85 ) {if(y>89) y=89;correction = _85YR50[y] - _85YR50[x] ;lbe=_85YR50[y];correctL=true;} + else if (( hue<=(_85YR50[x] + _7YR50[x])/2.0) && (hue > (_7YR50[x] + _55YR50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _7YR50[y] - _7YR50[x] ;lbe=_7YR50[y];correctL=true;} + else if (( hue<=(_7YR50[x] + _55YR50[x])/2.0) && (hue > (_55YR50[x] + _4YR50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _55YR50[y] - _55YR50[x] ; lbe=_55YR50[y];correctL=true;} + else if (( hue<=(_55YR50[x] + _4YR50[x])/2.0) && (hue > (_4YR50[x] + _25YR50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _4YR50[y] - _4YR50[x] ;lbe=_4YR50[y]; correctL=true;} + else if (( hue<=(_4YR50[x] + _25YR50[x])/2.0) && (hue > (_25YR50[x] + _10R50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _25YR50[y] - _25YR50[x] ;lbe=_25YR50[y];correctL=true;} + else if (( hue<=(_25YR50[x] + _10R50[x])/2.0) && (hue > (_10R50[x] + _9R50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10R50[y] - _10R50[x] ;lbe= _10R50[y]; correctL=true;} + else if (( hue<=(_10R50[x] + _9R50[x])/2.0) && (hue > (_9R50[x] + _7R50[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _9R50[y] - _9R50[x] ;lbe=_9R50[y];correctL=true;} + else if (( hue<=(_9R50[x] + _7R50[x])/2.0) && (hue > (_7R50[x] -0.035))&& x < 85) {if(y>89) y=89;correction = _7R50[y] - _7R50[x] ; lbe=_7R50[y];correctL=true;} + } + else if (lum <65.0) { + if( (hue <= (_10YR60[x] + 0.035)) && (hue > (_10YR60[x] + _85YR60[x])/2.0)) {;correction = _10YR60[y] - _10YR60[x] ;lbe= _10YR60[y];correctL=true;} + else if( (hue <= (_10YR60[x] + _85YR60[x])/2.0) && (hue >(_85YR60[x] + _7YR60[x])/2.0) ) {;correction = _85YR60[y] - _85YR60[x] ;lbe= _85YR60[y];correctL=true;} + else if (( hue<=(_85YR60[x] + _7YR60[x])/2.0) && (hue > (_7YR60[x] + _55YR60[x])/2.0)) {correction = _7YR60[y] - _7YR60[x] ;lbe=_7YR60[y];correctL=true;} + else if (( hue<=(_7YR60[x] + _55YR60[x])/2.0) && (hue > (_55YR60[x] + _4YR60[x])/2.0)) {correction = _55YR60[y] - _55YR60[x] ;lbe= _55YR60[y];correctL=true;} + else if (( hue<=(_55YR60[x] + _4YR60[x])/2.0) && (hue > (_4YR60[x] + _25YR60[x])/2.0)) {correction = _4YR60[y] - _4YR60[x] ;lbe=_4YR60[y]; correctL=true;} + else if (( hue<=(_4YR60[x] + _25YR60[x])/2.0) && (hue > (_25YR60[x] + _10R60[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _25YR60[y] - _25YR60[x] ;lbe=_25YR60[y];correctL=true;} + else if (( hue<=(_25YR60[x] + _10R60[x])/2.0) && (hue > (_10R60[x] + _9R60[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10R60[y] - _10R60[x] ;lbe= _10R60[y];correctL=true; } + else if (( hue<=(_10R60[x] + _9R60[x])/2.0) && (hue > (_9R60[x] + _7R60[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _9R60[y] - _9R60[x] ;lbe=_9R60[y];correctL=true;} + else if (( hue<=(_9R60[x] + _7R60[x])/2.0) && (hue > (_7R60[x] -0.035))&& x < 85) {if(y>89) y=89;correction = _7R60[y] - _7R60[x] ;lbe=_7R60[y]; correctL=true;} + } + else if (lum <75.0) { + if( (hue <= (_10YR70[x] + 0.035)) && (hue > (_10YR70[x] + _85YR70[x])/2.0)) {correction = _10YR70[y] - _10YR70[x] ;lbe= _10YR70[y];correctL=true;} + else if( (hue <= (_10YR70[x] + _85YR70[x])/2.0) && (hue >(_85YR70[x] + _7YR70[x])/2.0)) {correction = _85YR70[y] - _85YR70[x] ;lbe=_85YR70[y];correctL=true;} + if (( hue<=(_85YR70[x] + _7YR70[x])/2.0) && (hue > (_7YR70[x] + _55YR70[x])/2.0)) {correction = _7YR70[y] - _7YR70[x] ;lbe=_7YR70[y];correctL=true;} + else if (( hue<=(_7YR70[x] + _55YR70[x])/2.0) && (hue > (_55YR70[x] + _4YR70[x])/2.0)) {correction = _55YR70[y] - _55YR70[x] ;lbe=_55YR70[y];correctL=true; } + else if (( hue<=(_55YR70[x] + _4YR70[x])/2.0) && (hue > (_4YR70[x] + _25YR70[x])/2.0)) {correction = _4YR70[y] - _4YR70[x] ;lbe=_4YR70[y];correctL=true; } + else if (( hue<=(_4YR70[x] + _25YR70[x])/2.0) && (hue > (_25YR70[x] + _10R70[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _25YR70[y] - _25YR70[x] ;lbe= _25YR70[y];correctL=true;} + else if (( hue<=(_25YR70[x] + _10R70[x])/2.0) && (hue > (_10R70[x] + _9R70[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10R70[y] - _10R70[x] ;lbe= _10R70[y];correctL=true;} + else if (( hue<=(_10R70[x] + _9R70[x])/2.0) && (hue > (_9R70[x] + _7R70[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _9R70[y] - _9R70[x] ;lbe= _9R70[y] ;correctL=true;} + else if (( hue<=(_9R70[x] + _7R70[x])/2.0) && (hue > (_7R70[x] -0.035))&& x < 85) {if(y>89) y=89;correction = _7R70[y] - _7R70[x] ;lbe=_7R70[y];correctL=true; } + } + else if (lum <85.0) { + if( (hue <= (_10YR80[x] + 0.035)) && (hue > (_10YR80[x] + _85YR80[x])/2.0)) {correction = _10YR80[y] - _10YR80[x] ;lbe=_10YR80[y];correctL=true;} + else if( (hue <= (_10YR80[x] + _85YR80[x])/2.0) && (hue >(_85YR80[x] + _7YR80[x])/2.0)) {correction = _85YR80[y] - _85YR80[x] ;lbe= _85YR80[y];} + else if (( hue<=(_85YR80[x] + _7YR80[x])/2.0) && (hue > (_7YR80[x] + _55YR80[x])/2.0) && x<85) {if(y>89) y=89;correction = _7YR80[y] - _7YR80[x] ;lbe=_7YR80[y];correctL=true;} + else if (( hue<=(_7YR80[x] + _55YR80[x])/2.0) && (hue > (_55YR80[x] + _4YR80[x])/2.0) && x <45) {correction = _55YR80[y] - _55YR80[x] ;lbe=_55YR80[y];correctL=true; } + else if (( hue<=(_55YR80[x] + _4YR80[x])/2.0) && (hue > (_4YR80[x] - 0.035) && x<45)) {if(y>49) y=49;correction = _4YR80[y] - _4YR80[x] ; lbe=_4YR80[y] ;correctL=true;} + } + else if (lum <95.0) { + if( (hue <= (_10YR90[x] + 0.035)) && (hue > (_10YR90[x] -0.035) && x<85)) {if(y>89) y=89;correction = _10YR90[y] - _10YR90[x] ;lbe= _10YR90[y];correctL=true;} + else if ( hue<=(_85YR90[x] + 0.035) && hue > (_85YR90[x] -0.035) && x<85) {if(y>89) y=89;correction = _85YR90[y] - _85YR90[x] ;lbe=_85YR90[y];correctL=true;} + else if (( hue<=(_55YR90[x] + 0.035) && (hue > (_55YR90[x] - 0.035) && x<45))) {if(y>49) y=49;correction = _55YR90[y] - _55YR90[x] ;lbe= _55YR90[y];correctL=true; } + } + } + } + //end red yellow + + //Green yellow correction + else if(zone==3) { + if (lum >= 25.0) { + if (lum <35.0) { + if( (hue <= (_7G30[x] + 0.035)) && (hue > (_7G30[x] + _5G30[x])/2.0) ) {correction = _7G30[y] - _7G30[x] ;lbe=_7G30[y];correctL=true;} + else if( (hue <= (_7G30[x] + _5G30[x])/2.0) && (hue >(_5G30[x] + _25G30[x])/2.0)) {correction = _5G30[y] - _5G30[x] ;lbe= _5G30[y];correctL=true;} + else if (( hue<=(_25G30[x] + _5G30[x])/2.0) && (hue > (_25G30[x] + _1G30[x])/2.0)) {correction = _25G30[y] - _25G30[x] ;lbe=_25G30[y];correctL=true;} + else if (( hue<=(_1G30[x] + _25G30[x])/2.0) && (hue > (_1G30[x] + _10GY30[x])/2.0)) {correction = _1G30[y] - _1G30[x] ;lbe= _1G30[y];correctL=true;} + else if (( hue<=(_1G30[x] + _10GY30[x])/2.0) && (hue > (_10GY30[x] + _75GY30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10GY30[y] - _10GY30[x] ;lbe= _10GY30[y];correctL=true;} + else if (( hue<=(_10GY30[x] + _75GY30[x])/2.0) && (hue > (_75GY30[x] + _5GY30[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _75GY30[y] - _75GY30[x] ;lbe=_75GY30[y];correctL=true;} + else if (( hue<=(_5GY30[x] + _75GY30[x])/2.0) && (hue > (_5GY30[x] -0.035))&& x < 85) {if(y>89) y=89;correction = _5GY30[y] - _5GY30[x] ;lbe= _5GY30[y] ;correctL=true; } + } + else if (lum <45.0) { + if( (hue <= (_7G40[x] + 0.035)) && (hue > (_7G40[x] + _5G40[x])/2.0) ) {correction = _7G40[y] - _7G40[x] ;lbe= _7G40[y];correctL=true;} + else if( (hue <= (_7G40[x] + _5G40[x])/2.0) && (hue >(_5G40[x] + _25G40[x])/2.0)) {correction = _5G40[y] - _5G40[x] ;lbe=_5G40[y];correctL=true;} + else if (( hue<=(_25G40[x] + _5G40[x])/2.0) && (hue > (_25G40[x] + _1G40[x])/2.0)) {correction = _25G40[y] - _25G40[x] ;lbe=_25G40[y];correctL=true;} + else if (( hue<=(_1G40[x] + _25G40[x])/2.0) && (hue > (_1G40[x] + _10GY40[x])/2.0)) {correction = _1G40[y] - _1G40[x] ;lbe=_1G40[y];correctL=true; } + else if (( hue<=(_1G40[x] + _10GY40[x])/2.0) && (hue > (_10GY40[x] + _75GY40[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _10GY40[y] - _10GY40[x] ;lbe=_10GY40[y];correctL=true; } + else if (( hue<=(_10GY40[x] + _75GY40[x])/2.0) && (hue > (_75GY40[x] + _5GY40[x])/2.0)&& x < 85) {if(y>89) y=89;correction = _75GY40[y] - _75GY40[x] ;lbe=_75GY40[y];correctL=true;} + else if (( hue<=(_5GY40[x] + _75GY40[x])/2.0) && (hue > (_5GY40[x]-0.035)) && x < 85) {if(y>89) y=89; correction = _5GY40[y] - _5GY40[x] ;lbe=_5GY40[y];correctL=true; } // + } + else if (lum <55.0) { + if( (hue <= (_7G50[x] + 0.035)) && (hue > (_7G50[x] + _5G50[x])/2.0) ) {correction = _7G50[y] - _7G50[x] ;lbe=_7G50[y];correctL=true;} + else if( (hue <= (_7G50[x] + _5G50[x])/2.0) && (hue >(_5G50[x] + _25G50[x])/2.0)) {correction = _5G50[y] - _5G50[x] ;lbe=_5G50[y];correctL=true;} + else if (( hue<=(_25G50[x] + _5G50[x])/2.0) && (hue > (_25G50[x] + _1G50[x])/2.0)) {correction = _25G50[y] - _25G50[x] ;lbe= _25G50[y];correctL=true;} + else if (( hue<=(_1G50[x] + _25G50[x])/2.0) && (hue > (_1G50[x] + _10GY50[x])/2.0)) {correction = _1G50[y] - _1G50[x] ; lbe=_1G50[y];correctL=true;} + else if (( hue<=(_1G50[x] + _10GY50[x])/2.0) && (hue > (_10GY50[x] + _75GY50[x])/2.0)) {correction = _10GY50[y] - _10GY50[x] ;lbe= _10GY50[y];correctL=true;} + else if (( hue<=(_10GY50[x] + _75GY50[x])/2.0) && (hue > (_75GY50[x] + _5GY50[x])/2.0)) {correction = _75GY50[y] - _75GY50[x] ;lbe=_75GY50[y];correctL=true;} + else if (( hue<=(_5GY50[x] + _75GY50[x])/2.0) && (hue > (_5GY50[x] -0.035))) {correction = _5GY50[y] - _5GY50[x] ; lbe=_5GY50[y];correctL=true;} + } + else if (lum <65.0) { + if( (hue <= (_7G60[x] + 0.035)) && (hue > (_7G60[x] + _5G60[x])/2.0) ) {correction = _7G60[y] - _7G60[x] ;lbe=_7G60[y];correctL=true;} + else if( (hue <= (_7G60[x] + _5G60[x])/2.0) && (hue >(_5G60[x] + _25G60[x])/2.0)) {correction = _5G60[y] - _5G60[x] ;lbe=_5G60[y];correctL=true;} + else if (( hue<=(_25G60[x] + _5G60[x])/2.0) && (hue > (_25G60[x] + _1G60[x])/2.0)) {correction = _25G60[y] - _25G60[x] ;lbe=_25G60[y];correctL=true;} + else if (( hue<=(_1G60[x] + _25G60[x])/2.0) && (hue > (_1G60[x] + _10GY60[x])/2.0)) {correction = _1G60[y] - _1G60[x] ; lbe=_1G60[y];correctL=true;} + else if (( hue<=(_1G60[x] + _10GY60[x])/2.0) && (hue > (_10GY60[x] + _75GY60[x])/2.0)) {correction = _10GY60[y] - _10GY60[x] ;lbe= _10GY60[y];correctL=true;} + else if (( hue<=(_10GY60[x] + _75GY60[x])/2.0) && (hue > (_75GY60[x] + _5GY60[x])/2.0)) {correction = _75GY60[y] - _75GY60[x] ;lbe=_75GY60[y] ;correctL=true;} + else if (( hue<=(_5GY60[x] + _75GY60[x])/2.0) && (hue > (_5GY60[x] -0.035))) {correction = _5GY60[y] - _5GY60[x] ; lbe=_5GY60[y];correctL=true;} + } + else if (lum <75.0) { + if( (hue <= (_7G70[x] + 0.035)) && (hue > (_7G70[x] + _5G70[x])/2.0) ) {correction = _7G70[y] - _7G70[x] ;lbe= _7G70[y];correctL=true;} + else if( (hue <= (_7G70[x] + _5G70[x])/2.0) && (hue >(_5G70[x] + _25G70[x])/2.0)) {correction = _5G70[y] - _5G70[x] ;lbe= _5G70[y];correctL=true;} + else if (( hue<=(_25G70[x] + _5G70[x])/2.0) && (hue > (_25G70[x] + _1G70[x])/2.0)) {correction = _25G70[y] - _25G70[x] ;lbe=_25G70[y];correctL=true;} + else if (( hue<=(_1G70[x] + _25G70[x])/2.0) && (hue > (_1G70[x] + _10GY70[x])/2.0)) {correction = _1G70[y] - _1G70[x] ;lbe= _1G70[y] ;correctL=true;} + else if (( hue<=(_1G70[x] + _10GY70[x])/2.0) && (hue > (_10GY70[x] + _75GY70[x])/2.0)) {correction = _10GY70[y] - _10GY70[x] ; lbe=_10GY70[y];correctL=true;} + else if (( hue<=(_10GY70[x] + _75GY70[x])/2.0) && (hue > (_75GY70[x] + _5GY70[x])/2.0)) {correction = _75GY70[y] - _75GY70[x] ;lbe=_75GY70[y];correctL=true;} + else if (( hue<=(_5GY70[x] + _75GY70[x])/2.0) && (hue > (_5GY70[x] -0.035))) {correction = _5GY70[y] - _5GY70[x] ;lbe= _5GY70[y];correctL=true;} + } + else if (lum <85.0) { + if( (hue <= (_7G80[x] + 0.035)) && (hue > (_7G80[x] + _5G80[x])/2.0) ) {correction = _7G80[y] - _7G80[x] ;lbe=_7G80[y];correctL=true;} + else if( (hue <= (_7G80[x] + _5G80[x])/2.0) && (hue >(_5G80[x] + _25G80[x])/2.0)) {correction = _5G80[y] - _5G80[x] ;lbe=_5G80[y];correctL=true;} + else if (( hue<=(_25G80[x] + _5G80[x])/2.0) && (hue > (_25G80[x] + _1G80[x])/2.0)) {correction = _25G80[y] - _25G80[x] ;lbe=_25G80[y];correctL=true;} + else if (( hue<=(_1G80[x] + _25G80[x])/2.0) && (hue > (_1G80[x] + _10GY80[x])/2.0)) {correction = _1G80[y] - _1G80[x] ; lbe= _1G80[y];correctL=true;} + else if (( hue<=(_1G80[x] + _10GY80[x])/2.0) && (hue > (_10GY80[x] + _75GY80[x])/2.0)) {correction = _10GY80[y] - _10GY80[x] ;lbe=_10GY80[y];correctL=true; } + else if (( hue<=(_10GY80[x] + _75GY80[x])/2.0) && (hue > (_75GY80[x] + _5GY80[x])/2.0)) {correction = _75GY80[y] - _75GY80[x] ;lbe=_75GY80[y];correctL=true;} + else if (( hue<=(_5GY80[x] + _75GY80[x])/2.0) && (hue > (_5GY80[x] -0.035))) {correction = _5GY80[y] - _5GY80[x] ; lbe=_5GY80[y];correctL=true;} + } + } + } + //end green yellow + + //Red purple correction : only for L < 30 + else if(zone==4) { + if (lum > 5.0) { + if (lum < 15.0) { + if( (hue <= (_5R10[x] + 0.035)) && (hue > (_5R10[x] - 0.043)) && x<45) {if(y>44) y=44;correction = _5R10[y] - _5R10[x] ;lbe=_5R10[y];correctL=true;} + else if( (hue <= (_25R10[x] + 0.043)) && (hue >(_25R10[x] + _10RP10[x])/2.0) && x<45 ) {if(y>44) y=44;correction = _25R10[y] - _25R10[x] ;lbe= _25R10[y];correctL=true;} + else if ( (hue <=(_25R10[x] + _10RP10[x])/2.0) && (hue > (_10RP10[x] -0.035) ) && x<45){if(y>44) y=44; correction = _10RP10[y] - _10RP10[x] ;lbe=_10RP10[y];correctL=true;} + } + else if (lum <25.0) { + if( (hue <= (_5R20[x] + 0.035)) && (hue > (_5R20[x] + _25R20[x])/2.0) && x<70 ) {if(y>70) y=70;correction = _5R20[y] - _5R20[x] ;lbe= _5R20[y];correctL=true;} + else if( (hue <= (_5R20[x] + _25R20[x])/2.0) && (hue >(_10RP20[x] + _25R20[x])/2.0) && x<70) {if(y>70) y=70;correction = _25R20[y] - _25R20[x] ;lbe=_25R20[y];correctL=true;} + else if (( hue<=(_10RP20[x] + _25R20[x])/2.0) && (hue > (_10RP20[x] -0.035)) && x<70) {if(y>70) y=70; correction = _10RP20[y] - _10RP20[x] ;lbe=_10RP20[y];correctL=true;} + } + else if (lum <35.0) { + if( (hue <= (_5R30[x] + 0.035)) && (hue > (_5R30[x] + _25R30[x])/2.0) && x<85 ) {if(y>85) y=85;correction = _5R30[y] - _5R30[x] ;lbe= _5R30[y];correctL=true;} + else if( (hue <= (_5R30[x] + _25R30[x])/2.0) && (hue >(_10RP30[x] + _25R30[x])/2.0) && x< 85) {if(y>85) y=85;correction = _25R30[y] - _25R30[x] ;lbe=_25R30[y];correctL=true;} + else if (( hue<=(_10RP30[x] + _25R30[x])/2.0) && (hue > (_10RP30[x] -0.035)) && x<85) {if(y>85) y=85; correction = _10RP30[y] - _10RP30[x] ;lbe= _10RP30[y];correctL=true;} + } + } + } + //end red purple + } + + + /* + * SkinSat + * Copyright (c)2011 Jacques Desmis + * + * skin color: mixed from NX2 skin color palette, Von Luschan, and photos of people white, + * black, yellow....there are some little exceptions...cover 99% case + * pay attention to white balance, and do not change hue and saturation, upstream of the modification + * + */ + void Color::SkinSat (float lum, float hue, float chrom, float &satreduc) { + + // to be adapted...by tests + float reduction=0.3f; // use "reduction" for "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1 + float extendedreduction=0.4f; // use "extendedreduction" for wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation + float extendedreduction2=0.6f; // use "extendedreduction2" for wide area for transition + + float C9=8.0, C8=15.0, C7=12.0, C4=7.0, C3=5.0, C2=5.0, C1=5.0; + float H9=0.05, H8=0.25, H7=0.1, H4=0.02, H3=0.02, H2=0.1, H1=0.1, H10=-0.2,H11=-0.2; //H10 and H11 are curious...H11=-0.8 ?? + + if (lum >= 85.f) { + if((hue > (0.78f-H9) && hue < (1.18f+H9)) && (chrom > 8.f && chrom < (14.f+C9))) satreduc=reduction; + else if (lum >= 92.f) { + if((hue > 0.8f && hue < 1.65f) && (chrom > 7.f && chrom < (15.f))) satreduc=extendedreduction; + else if ((hue > -0.1f && hue < 1.65f) && (chrom > 7.f && chrom < (18.f))) satreduc=extendedreduction2; + } + else if ((hue > 0.7f && hue < 1.4f) && (chrom > 7.f && chrom < (26.f+C9))) satreduc=extendedreduction; + else if (lum < 92.f && (hue > 0.f && hue < 1.65f) && (chrom > 7.f && chrom < (35.f+C9))) satreduc=extendedreduction2; + } + else if (lum >= 70.f) { + if((hue > 0.4f && hue < (1.04f+H8)) && (chrom > 8.f && chrom < (35.f+C8))) satreduc=reduction; + else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; + else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; + } + else if (lum >= 52.f) { + if((hue > 0.3f && hue < (1.27f+H7)) && (chrom > 11.f && chrom < (35.f+C7))) satreduc=reduction; + else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; + else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; + } + else if (lum >= 35.f) { + if((hue > 0.3f && hue < (1.25f+H4)) && (chrom > 13.f && chrom < (37.f+C4))) satreduc=reduction; + else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; + else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; + } + else if (lum >= 20.f) { + if((hue > 0.3f && hue < (1.2f+H3)) && (chrom > 7.f && chrom <(35.f+C3) )) satreduc=reduction; + else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; + else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; + } + else if (lum > 10.f) { + if((hue > (0.f + H10) && hue < (0.95f +H2)) && (chrom > 8.f && chrom < (23.f+C2))) satreduc=reduction; + else if ((hue > (0.02f+H11) && hue < 1.f) && (chrom > 7.f && chrom < (35.f+C1) )) satreduc=extendedreduction; + else if ((hue > (0.02f+H11) && hue < 1.6f) && (chrom > 7.f && chrom < (45.f+C1) )) satreduc=extendedreduction2; + } + else { + if((hue > (0.02f + H10) && hue < (0.9f+H1)) && (chrom > 8.f && chrom < (23.f+C1))) satreduc=reduction; // no data : extrapolate + else if ((hue > (0.02f+H11) && hue < 1.f) && (chrom > 7.f && chrom < (35.f+C1) )) satreduc=extendedreduction; + else if ((hue > (0.02f+H11) && hue < 1.6f) && (chrom > 7.f && chrom < (45.f+C1) )) satreduc=extendedreduction2; + + } + + } + + /* + * Munsell Lch correction + * Copyright (c) 2011 Jacques Desmis + * + * data (Munsell ==> Lab) obtained with WallKillcolor and http://www.cis.rit.edu/research/mcsl2/online/munsell.php + * each LUT give Hue in function of C, for each color Munsell and Luminance + * eg: _6PB20 : color Munsell 6PB for L=20 c=5 c=45 c=85 c=125..139 when possible: interpolation betwwen values + * no value for C<5 (gray) + * low memory footprint -- maximum: 195 LUTf * 140 values + * errors due to small number of samples in LUT and linearization are very low (1 to 2%) + * errors due to a different illuminant "Daylight" than "C" are low, about 10%. For example, a theoretical correction of 0.1 radian will be made with a real correction of 0.09 or 0.11 depending on the color illuminant D50 + * errors due to the use of a very different illuminant "C", for example illuminant "A" (tungsten) are higher, about 20%. Theoretical correction of 0.52 radians will be made with a real correction of 0.42 + */ + void Color::initMunsell () { + #ifdef _DEBUG + MyTime t1e,t2e; + t1e.set(); + #endif + + const int maxInd = 140; + const int maxInd2 = 90; + const int maxInd3 = 50; + + //blue for sky + _5B40(maxInd2); + _5B40.clear(); + for (int i=0; i5) _5B40[i] = -2.3 + 0.0025*(i-5); + else if (i<90 && i>=45) _5B40[i] = -2.2 + 0.00*(i-45); + } + //printf("5B %1.2f %1.2f\n",_5B40[44],_5B40[89]); + _5B50(maxInd2); + _5B50.clear(); + for (int i=0; i5) _5B50[i] = -2.34 + 0.0025*(i-5); + else if (i<90 && i>=45) _5B50[i] = -2.24+0.0003*(i-45); + } + //printf("5B %1.2f %1.2f\n",_5B50[44],_5B50[89]); + _5B60(maxInd2); + _5B60.clear(); + for (int i=0; i5) _5B60[i] = -2.4 + 0.003*(i-5); + else if (i<90 && i>=45) _5B60[i] = -2.28+0.0005*(i-45); + } + //printf("5B %1.2f %1.2f\n",_5B60[44],_5B60[89]); + _5B70(maxInd2); + _5B70.clear(); + for (int i=0; i5) _5B70[i] = -2.41 + 0.00275*(i-5); + else if (i<90 && i>=45) _5B70[i] = -2.30+0.00025*(i-45); + } + //printf("5B %1.2f %1.2f\n",_5B70[44],_5B70[89]); + _5B80(maxInd3); + _5B80.clear(); + for (int i=0; i5) _5B80[i] = -2.45 +0.003*(i-5); + } + //printf("5B %1.2f\n",_5B80[49]); + + _7B40(maxInd2); + _7B40.clear(); + for (int i=0; i5) _7B40[i] = -2.15 + 0.0027*(i-5); + else if (i<90 && i>=45) _7B40[i] = -2.04 + 0.00*(i-45); + } + //printf("7B %1.2f %1.2f\n",_7B40[44],_7B40[89]); + _7B50(maxInd2); + _7B50.clear(); + for (int i=0; i5) _7B50[i] = -2.20 + 0.003*(i-5); + else if (i<90 && i>=45) _7B50[i] = -2.08 + 0.001*(i-45); + } + //printf("7B %1.2f %1.2f\n",_7B50[44],_7B50[79]); + _7B60(maxInd2); + _7B60.clear(); + for (int i=0; i5) _7B60[i] = -2.26 + 0.0035*(i-5); + else if (i<90 && i>=45) _7B60[i] = -2.12 + 0.001*(i-45); + } + //printf("7B %1.2f %1.2f\n",_7B60[44],_7B60[79]); + _7B70(maxInd2); + _7B70.clear(); + for (int i=0; i5) _7B70[i] = -2.28 + 0.003*(i-5); + else if (i<90 && i>=45) _7B70[i] = -2.16 + 0.0015*(i-45); + } + //printf("7B %1.2f %1.2f\n",_7B70[44],_7B70[64]); + _7B80(maxInd3); + _7B80.clear(); + for (int i=0; i5) _7B80[i] = -2.30 +0.0028*(i-5); + } + //printf("5B %1.2f\n",_7B80[49]); + + _9B40(maxInd2); + _9B40.clear(); + for (int i=0; i5) _9B40[i] = -1.99 + 0.0022*(i-5); + else if (i<90 && i>=45) _9B40[i] = -1.90 + 0.0008*(i-45); + } + //printf("9B %1.2f %1.2f\n",_9B40[44],_9B40[69]); + _9B50(maxInd2); + _9B50.clear(); + for (int i=0; i5) _9B50[i] = -2.04 + 0.0025*(i-5); + else if (i<90 && i>=45) _9B50[i] = -1.94 + 0.0013*(i-45); + } + //printf("9B %1.2f %1.2f\n",_9B50[44],_9B50[77]); + _9B60(maxInd2); + _9B60.clear(); + for (int i=0; i5) _9B60[i] = -2.10 + 0.0033*(i-5); + else if (i<90 && i>=45) _9B60[i] = -1.97 + 0.001*(i-45); + } + //printf("9B %1.2f %1.2f\n",_9B60[44],_9B60[79]); + _9B70(maxInd2); + _9B70.clear(); + for (int i=0; i5) _9B70[i] = -2.12 + 0.003*(i-5); + else if (i<90 && i>=45) _9B70[i] = -2.00 + 0.001*(i-45); + } + //printf("9B %1.2f %1.2f\n",_9B70[44],_9B70[54]); + _9B80(maxInd3); + _9B80.clear(); + for (int i=0; i5) _9B80[i] = -2.16 +0.0025*(i-5); + } + //printf("9B %1.2f\n",_9B80[49]); + + _10B40(maxInd2); + _10B40.clear(); + for (int i=0; i5) _10B40[i] = -1.92 + 0.0022*(i-5); + else if (i<90 && i>=45) _10B40[i] = -1.83 + 0.0012*(i-45); + } + //printf("10B %1.2f %1.2f\n",_10B40[44],_10B40[76]); + _10B50(maxInd2); + _10B50.clear(); + for (int i=0; i5) _10B50[i] = -1.95 + 0.0022*(i-5); + else if (i<90 && i>=45) _10B50[i] = -1.86 + 0.0008*(i-45); + } + //printf("10B %1.2f %1.2f\n",_10B50[44],_10B50[85]); + _10B60(maxInd2); + _10B60.clear(); + for (int i=0; i5) _10B60[i] = -2.01 + 0.0027*(i-5); + else if (i<90 && i>=45) _10B60[i] = -1.90 + 0.0012*(i-45); + } + //printf("10B %1.2f %1.2f\n",_10B60[44],_10B60[70]); + _10B70(maxInd3); + _10B70.clear(); + for (int i=0; i5) _10B70[i] = -2.03 +0.0025*(i-5); + } + //printf("10B %1.2f\n",_10B70[49]); + _10B80(maxInd3); + _10B80.clear(); + for (int i=0; i5) _10B80[i] = -2.08 +0.0032*(i-5); + } + //printf("10B %1.2f\n",_10B80[39]); + + _05PB40(maxInd2); + _05PB40.clear(); + for (int i=0; i5) _05PB40[i] = -1.87 + 0.0022*(i-5); + else if (i<90 && i>=45) _05PB40[i] = -1.78 + 0.0015*(i-45); + } + //printf("05PB %1.2f %1.2f\n",_05PB40[44],_05PB40[74]); + _05PB50(maxInd2); + _05PB50.clear(); + for (int i=0; i5) _05PB50[i] = -1.91 + 0.0022*(i-5); + else if (i<90 && i>=45) _05PB50[i] = -1.82 + 0.001*(i-45); + } + //printf("05PB %1.2f %1.2f\n",_05PB50[44],_05PB50[85]); + _05PB60(maxInd2); + _05PB60.clear(); + for (int i=0; i5) _05PB60[i] = -1.96 + 0.0027*(i-5); + else if (i<90 && i>=45) _05PB60[i] = -1.85 + 0.0013*(i-45); + } + //printf("05PB %1.2f %1.2f\n",_05PB60[44],_05PB60[70]); + _05PB70(maxInd2); + _05PB70.clear(); + for (int i=0; i5) _05PB70[i] = -1.99 + 0.0027*(i-5); + else if (i<90 && i>=45) _05PB70[i] = -1.88 + 0.001*(i-45); + } + //printf("05PB %1.2f %1.2f\n",_05PB70[44],_05PB70[54]); + _05PB80(maxInd3); + _05PB80.clear(); + for (int i=0; i5) _05PB80[i] = -2.03 +0.003*(i-5); + } + //printf("05PB %1.2f\n",_05PB80[39]); + + + + //blue purple correction + //between 15PB to 4P + //maximum deviation 75PB + + //15PB + _15PB10(maxInd3); + _15PB10.clear(); + for (int i=0; i5) _15PB10[i] = -1.66 +0.0035*(i-5); + } + //printf("15 %1.2f\n",_15PB10[49]); + _15PB20(maxInd2); + _15PB20.clear(); + for (int i=0; i5) _15PB20[i] = -1.71 +0.00275*(i-5); + else if (i<90 && i>=45) _15PB20[i] = -1.60+0.0012*(i-45); + } + //printf("15 %1.2f %1.2f\n",_15PB20[44],_15PB20[89]); + + _15PB30(maxInd2); + _15PB30.clear(); + for (int i=0; i5) _15PB30[i] = -1.75 +0.0025*(i-5); + else if (i<90 && i>=45) _15PB30[i] = -1.65+0.002*(i-45); + } + //printf("15 %1.2f %1.2f\n",_15PB30[44],_15PB30[89]); + + _15PB40(maxInd2); + _15PB40.clear(); + for (int i=0; i5) _15PB40[i] = -1.79 +0.002*(i-5); + else if (i<90 && i>=45) _15PB40[i] = -1.71+0.002*(i-45); + } + //printf("15 %1.2f %1.2f\n",_15PB40[44],_15PB40[89]); + + _15PB50(maxInd2); + _15PB50.clear(); + for (int i=0; i5) _15PB50[i] = -1.82 +0.002*(i-5); + else if (i<90 && i>=45) _15PB50[i] = -1.74+0.0011*(i-45); + } + //printf("15 %1.2f %1.2f\n",_15PB50[44],_15PB50[89]); + + _15PB60(maxInd2); + _15PB60.clear(); + for (int i=0; i5) _15PB60[i] = -1.87 +0.0025*(i-5); + else if (i<90 && i>=45) _15PB60[i] = -1.77+0.001*(i-45); + } + //printf("15 %1.2f %1.2f\n",_15PB60[44],_15PB60[89]); + _15PB70(maxInd3); + _15PB70.clear(); + for (int i=0; i5) _15PB70[i] = -1.90 +0.0027*(i-5); + } + // printf("15 %1.2f\n",_15PB70[49]); + _15PB80(maxInd3); + _15PB80.clear(); + for (int i=0; i5) _15PB80[i] = -1.93 +0.0027*(i-5); + } + //printf("15 %1.2f %1.2f\n",_15PB80[38], _15PB80[49]); + + //3PB + _3PB10(maxInd2); + _3PB10.clear(); + for (int i=0; i5) _3PB10[i] = -1.56 +0.005*(i-5); + else if (i<90 && i>=45) _3PB10[i] = -1.36+0.001*(i-45); + } + //printf("30 %1.2f %1.2f\n",_3PB10[44],_3PB10[89]); + + _3PB20(maxInd2); + _3PB20.clear(); + for (int i=0; i5) _3PB20[i] = -1.59 +0.00275*(i-5); + else if (i<90 && i>=45) _3PB20[i] = -1.48+0.003*(i-45); + } + //printf("30 %1.2f %1.2f\n",_3PB20[44],_3PB20[89]); + + _3PB30(maxInd2); + _3PB30.clear(); + for (int i=0; i5) _3PB30[i] = -1.62 +0.00225*(i-5); + else if (i<90 && i>=45) _3PB30[i] = -1.53+0.0032*(i-45); + } + //printf("30 %1.2f %1.2f\n",_3PB30[44],_3PB30[89]); + + _3PB40(maxInd2); + _3PB40.clear(); + for (int i=0; i5) _3PB40[i] = -1.64 +0.0015*(i-5); + else if (i<90 && i>=45) _3PB40[i] = -1.58+0.0025*(i-45); + } + //printf("30 %1.2f %1.2f\n",_3PB40[44],_3PB40[89]); + + _3PB50(maxInd2); + _3PB50.clear(); + for (int i=0; i5) _3PB50[i] = -1.69 +0.00175*(i-5); + else if (i<90 && i>=45) _3PB50[i] = -1.62+0.002*(i-45); + } + //printf("30 %1.2f %1.2f\n",_3PB50[44],_3PB50[89]); + + _3PB60(maxInd2); + _3PB60.clear(); + for (int i=0; i5) _3PB60[i] = -1.73 +0.002*(i-5); + else if (i<90 && i>=45) _3PB60[i] = -1.65+0.0012*(i-45); + } + //printf("30 %1.2f %1.2f\n",_3PB60[44],_3PB60[89]); + _3PB70(maxInd3); + _3PB70.clear(); + for (int i=0; i5) _3PB70[i] = -1.76 +0.002*(i-5); + } + //printf("30 %1.2f\n",_3PB70[49]); + _3PB80(maxInd3); + _3PB80.clear(); + for (int i=0; i5) _3PB80[i] = -1.78 +0.0025*(i-5); + } + //printf("30 %1.2f %1.2f\n",_3PB80[38], _3PB80[49]); + + //45PB + _45PB10(maxInd2); + _45PB10.clear(); + for (int i=0; i5) _45PB10[i] = -1.46 +0.0045*(i-5); + else if (i<90 && i>=45) _45PB10[i] = -1.28+0.0025*(i-45); + } + //printf("45 %1.2f %1.2f\n",_45PB10[44],_45PB10[89]); + + _45PB20(maxInd2); + _45PB20.clear(); + for (int i=0; i5) _45PB20[i] = -1.48 +0.00275*(i-5); + else if (i<90 && i>=45) _45PB20[i] = -1.37+0.0025*(i-45); + } + //printf("45 %1.2f %1.2f\n",_45PB20[44],_45PB20[89]); + + _45PB30(maxInd2); + _45PB30.clear(); + for (int i=0; i5) _45PB30[i] = -1.51 +0.00175*(i-5); + else if (i<90 && i>=45) _45PB30[i] = -1.44+0.0035*(i-45); + } + //printf("45 %1.2f %1.2f\n",_45PB30[44],_45PB30[89]); + + _45PB40(maxInd2); + _45PB40.clear(); + for (int i=0; i5) _45PB40[i] = -1.52 +0.001*(i-5); + else if (i<90 && i>=45) _45PB40[i] = -1.48+0.003*(i-45); + } + //printf("45 %1.2f %1.2f\n",_45PB40[44],_45PB40[89]); + + _45PB50(maxInd2); + _45PB50.clear(); + for (int i=0; i5) _45PB50[i] = -1.55 +0.001*(i-5); + else if (i<90 && i>=45) _45PB50[i] = -1.51+0.0022*(i-45); + } + //printf("45 %1.2f %1.2f\n",_45PB50[44],_45PB50[89]); + + _45PB60(maxInd2); + _45PB60.clear(); + for (int i=0; i5) _45PB60[i] = -1.6 +0.0015*(i-5); + else if (i<90 && i>=45) _45PB60[i] = -1.54+0.001*(i-45); + } + //printf("45 %1.2f %1.2f\n",_45PB60[44],_45PB60[89]); + _45PB70(maxInd3); + _45PB70.clear(); + for (int i=0; i5) _45PB70[i] = -1.63 +0.0017*(i-5); + } + //printf("45 %1.2f\n",_45PB70[49]); + _45PB80(maxInd3); + _45PB80.clear(); + for (int i=0; i5) _45PB80[i] = -1.67 +0.0025*(i-5); + } + //printf("45 %1.2f %1.2f\n",_45PB80[38], _45PB80[49]); + + //_6PB + _6PB10(maxInd); + _6PB10.clear(); + for (int i=0; i140 + if (i<45 && i>5) _6PB10[i] = -1.33 +0.005*(i-5); + else if (i<85 && i>=45) _6PB10[i] = -1.13+0.0045*(i-45); + else if (i<140 && i >=85) _6PB10[i] = -0.95+0.0015*(i-85); + } + //printf("60 %1.2f %1.2f %1.2f\n",_6PB10[44],_6PB10[84],_6PB10[139]); + + _6PB20(maxInd); + _6PB20.clear(); + for (int i=0; i140 + if (i<45 && i>5) _6PB20[i] = -1.36 +0.004*(i-5); + else if (i<85 && i>=45) _6PB20[i] = -1.20+0.00375*(i-45); + else if (i<140 && i >=85) _6PB20[i] = -1.05+0.0017*(i-85); + } + //printf("60 %1.2f %1.2f %1.2f\n",_6PB20[44],_6PB20[84],_6PB20[139]); + + _6PB30(maxInd); + _6PB30.clear(); + for (int i=0; i140 + if (i<45 && i>5) _6PB30[i] = -1.38 +0.00225*(i-5); + else if (i<85 && i>=45) _6PB30[i] = -1.29+0.00375*(i-45); + else if (i<140 && i >=85) _6PB30[i] = -1.14+0.002*(i-85); + } + //printf("60 %1.2f %1.2f %1.2f\n",_6PB30[44],_6PB30[84],_6PB30[139]); + + _6PB40(maxInd); + _6PB40.clear(); + for (int i=0; i140 + if (i<45 && i>5) _6PB40[i] = -1.39 +0.00125*(i-5); + else if (i<85 && i>=45) _6PB40[i] = -1.34+0.00275*(i-45); + else if (i<140 && i >=85) _6PB40[i] = -1.23+0.002*(i-85); + } + //printf("60 %1.2f %1.2f %1.2f\n",_6PB40[44],_6PB40[84],_6PB40[139]); + + _6PB50(maxInd2);//limits -1.3 -1.11 + _6PB50.clear(); + for (int i=0; i5) _6PB50[i] = -1.43 +0.00125*(i-5); + else if (i<90 && i>=45) _6PB50[i] = -1.38+0.00225*(i-45); + } + //printf("60 %1.2f %1.2f \n",_6PB50[44],_6PB50[89]); + + _6PB60(maxInd2);//limits -1.3 -1.11 + _6PB60.clear(); + for (int i=0; i5) _6PB60[i] = -1.46 +0.0012*(i-5); + else if (i<90 && i>=45) _6PB60[i] = -1.40+0.000875*(i-45); + } + //printf("60 %1.2f %1.2f\n",_6PB60[44],_6PB60[89]); + _6PB70(maxInd3); + _6PB70.clear(); + for (int i=0; i5) _6PB70[i] = -1.49 +0.0018*(i-5); + } + //printf("6 %1.2f\n",_6PB70[49]); + _6PB80(maxInd3); + _6PB80.clear(); + for (int i=0; i5) _6PB80[i] = -1.52 +0.0022*(i-5); + } + //printf("6 %1.2f %1.2f\n",_6PB80[38], _6PB80[49]); + + + //_75PB : notation Munsell for maximum deviation blue purple + _75PB10(maxInd);//limits hue -1.23 -0.71 _75PBx x=Luminance eg_75PB10 for L >5 and L<=15 + _75PB10.clear(); + for (int i=0; i140 + if (i<45 && i>5) _75PB10[i] = -1.23 +0.0065*(i-5); + else if (i<85 && i>=45) _75PB10[i] = -0.97+0.00375*(i-45); + else if (i<140 && i >=85) _75PB10[i] = -0.82+0.0015*(i-85); + } + //printf("75 %1.2f %1.2f %1.2f\n",_75PB10[44],_75PB10[84],_75PB10[139]); + + _75PB20(maxInd);//limits -1.24 -0.79 for L>15 <=25 + _75PB20.clear(); + for (int i=0; i5) _75PB20[i] = -1.24 +0.004*(i-5); + else if (i<85 && i>=45) _75PB20[i] = -1.08+0.00425*(i-45); + else if (i<140 && i >=85) _75PB20[i] = -0.91+0.0017*(i-85); + } + //printf("75 %1.2f %1.2f %1.2f\n",_75PB20[44],_75PB20[84],_75PB20[139]); + + _75PB30(maxInd);//limits -1.25 -0.85 + _75PB30.clear(); + for (int i=0; i5) _75PB30[i] = -1.25 +0.00275*(i-5); + else if (i<85 && i>=45) _75PB30[i] = -1.14+0.004*(i-45); + else if (i<140 && i >=85) _75PB30[i] = -0.98+0.0015*(i-85); + } + //printf("75 %1.2f %1.2f %1.2f\n",_75PB30[44],_75PB30[84],_75PB30[139]); + + _75PB40(maxInd);//limits -1.27 -0.92 + _75PB40.clear(); + for (int i=0; i5) _75PB40[i] = -1.27 +0.002*(i-5); + else if (i<85 && i>=45) _75PB40[i] = -1.19+0.003*(i-45); + else if (i<140 && i >=85) _75PB40[i] = -1.07+0.0022*(i-85); + } + //printf("75 %1.2f %1.2f %1.2f\n",_75PB40[44],_75PB40[84],_75PB40[139]); + + _75PB50(maxInd2);//limits -1.3 -1.11 + _75PB50.clear(); + for (int i=0; i5) _75PB50[i] = -1.3 +0.00175*(i-5); + else if (i<90 && i>=45) _75PB50[i] = -1.23+0.0025*(i-45); + } + //printf("75 %1.2f %1.2f\n",_75PB50[44],_75PB50[89]); + + _75PB60(maxInd2); + _75PB60.clear(); + for (int i=0; i5) _75PB60[i] = -1.32 +0.0015*(i-5); + else if (i<90 && i>=45) _75PB60[i] = -1.26+0.002*(i-45); + } + //printf("75 %1.2f %1.2f \n",_75PB60[44],_75PB60[89]); + + _75PB70(maxInd3); + _75PB70.clear(); + for (int i=0; i5) _75PB70[i] = -1.34 +0.002*(i-5); + } + _75PB80(maxInd3); + _75PB80.clear(); + for (int i=0; i5) _75PB80[i] = -1.35 +0.00125*(i-5); + } + + + _9PB10(maxInd); + _9PB10.clear(); + for (int i=0; i140 + if (i<45 && i>5) _9PB10[i] = -1.09 +0.00475*(i-5); + else if (i<85 && i>=45) _9PB10[i] = -0.9+0.003*(i-45); + else if (i<140 && i >=85) _9PB10[i] = -0.78+0.0013*(i-85); + } + //printf("90 %1.2f %1.2f %1.2f\n",_9PB10[44],_9PB10[84],_9PB10[139]); + + _9PB20(maxInd); + _9PB20.clear(); + for (int i=0; i140 + if (i<45 && i>5) _9PB20[i] = -1.12 +0.0035*(i-5); + else if (i<85 && i>=45) _9PB20[i] = -0.98+0.00325*(i-45); + else if (i<140 && i >=85) _9PB20[i] = -0.85+0.0015*(i-85); + } + //printf("90 %1.2f %1.2f %1.2f\n",_9PB20[44],_9PB20[84],_9PB20[139]); + + _9PB30(maxInd); + _9PB30.clear(); + for (int i=0; i140 + if (i<45 && i>5) _9PB30[i] = -1.14 +0.0028*(i-5); + else if (i<85 && i>=45) _9PB30[i] = -1.03+0.003*(i-45); + else if (i<140 && i >=85) _9PB30[i] = -0.91+0.0017*(i-85); + } + //printf("90 %1.2f %1.2f %1.2f\n",_9PB30[44],_9PB30[84],_9PB30[139]); + + _9PB40(maxInd); + _9PB40.clear(); + for (int i=0; i140 + if (i<45 && i>5) _9PB40[i] = -1.16 +0.002*(i-5); + else if (i<85 && i>=45) _9PB40[i] = -1.08+0.00275*(i-45); + else if (i<140 && i >=85) _9PB40[i] = -0.97+0.0016*(i-85); + } + //printf("90 %1.2f %1.2f %1.2f\n",_9PB40[44],_9PB40[84],_9PB40[139]); + + _9PB50(maxInd2); + _9PB50.clear(); + for (int i=0; i5) _9PB50[i] = -1.19 +0.00175*(i-5); + else if (i<90 && i>=45) _9PB50[i] = -1.12+0.00225*(i-45); + } + //printf("90 %1.2f %1.2f \n",_9PB50[44],_9PB50[84]); + + _9PB60(maxInd2); + _9PB60.clear(); + for (int i=0; i5) _9PB60[i] = -1.21 +0.0015*(i-5); + else if (i<90 && i>=45) _9PB60[i] = -1.15+0.002*(i-45); + } + //printf("90 %1.2f %1.2f \n",_9PB60[44],_9PB60[89]); + _9PB70(maxInd3); + _9PB70.clear(); + for (int i=0; i5) _9PB70[i] = -1.23 +0.0018*(i-5); + } + //printf("9 %1.2f\n",_9PB70[49]); + _9PB80(maxInd3); + _9PB80.clear(); + for (int i=0; i5) _9PB80[i] = -1.24 +0.002*(i-5); + } + //printf("9 %1.2f %1.2f\n",_9PB80[38], _9PB80[49]); + + + //10PB + _10PB10(maxInd); + _10PB10.clear(); + for (int i=0; i5) _10PB10[i] = -1.02 +0.00425*(i-5); + else if (i<85 && i>=45) _10PB10[i] = -0.85+0.0025*(i-45); + else if (i<140 && i >=85) _10PB10[i] = -0.75+0.0012*(i-85); + } + //printf("10 %1.2f %1.2f %1.2f\n",_10PB10[44],_10PB10[84],_10PB10[139]); + + _10PB20(maxInd); + _10PB20.clear(); + for (int i=0; i5) _10PB20[i] = -1.05 +0.00325*(i-5); + else if (i<85 && i>=45) _10PB20[i] = -0.92+0.00275*(i-45); + else if (i<140 && i >=85) _10PB20[i] = -0.81+0.0014*(i-85); + } + //printf("10 %1.2f %1.2f %1.2f\n",_10PB20[44],_10PB20[84],_10PB20[139]); + + _10PB30(maxInd); + _10PB30.clear(); + for (int i=0; i5) _10PB30[i] = -1.07 +0.00275*(i-5); + else if (i<85 && i>=45) _10PB30[i] = -0.96+0.0025*(i-45); + else if (i<140 && i >=85) _10PB30[i] = -0.86+0.0015*(i-85); + } + //printf("10 %1.2f %1.2f %1.2f\n",_10PB30[44],_10PB30[84],_10PB30[139]); + + _10PB40(maxInd); + _10PB40.clear(); + for (int i=0; i5) _10PB40[i] = -1.09 +0.002*(i-5); + else if (i<85 && i>=45) _10PB40[i] = -1.01+0.00225*(i-45); + else if (i<140 && i >=85) _10PB40[i] = -0.92+0.0016*(i-85); + } + //printf("10 %1.2f %1.2f %1.2f\n",_10PB40[44],_10PB40[84],_10PB40[139]); + + _10PB50(maxInd2); + _10PB50.clear(); + for (int i=0; i5) _10PB50[i] = -1.12 +0.00175*(i-5); + else if (i<90 && i>=45) _10PB50[i] = -1.05+0.00225*(i-45); + } + //printf("10 %1.2f %1.2f\n",_10PB50[44],_10PB50[84]); + + _10PB60(maxInd2); + _10PB60.clear(); + for (int i=0; i5) _10PB60[i] = -1.14 +0.0015*(i-5); + else if (i<90 && i>=45) _10PB60[i] = -1.08+0.00225*(i-45); + } + //printf("10 %1.2f %1.2f\n",_10PB60[44],_10PB60[89]); + + + //1P + _1P10(maxInd); + _1P10.clear(); + for (int i=0; i5) _1P10[i] = -0.96 +0.00375*(i-5); + else if (i<85 && i>=45) _1P10[i] = -0.81+0.00225*(i-45); + else if (i<140 && i >=85) _1P10[i] = -0.72+0.001*(i-85); + } + //printf("1P %1.2f %1.2f %1.2f\n",_1P10[44],_1P10[84],_1P10[139]); + + _1P20(maxInd); + _1P20.clear(); + for (int i=0; i5) _1P20[i] = -1.0 +0.00325*(i-5); + else if (i<85 && i>=45) _1P20[i] = -0.87+0.0025*(i-45); + else if (i<140 && i >=85) _1P20[i] = -0.77+0.0012*(i-85); + } + //printf("1P %1.2f %1.2f %1.2f\n",_1P20[44],_1P20[84],_1P20[139]); + + _1P30(maxInd); + _1P30.clear(); + for (int i=0; i5) _1P30[i] = -1.02 +0.00275*(i-5); + else if (i<85 && i>=45) _1P30[i] = -0.91+0.00225*(i-45); + else if (i<140 && i >=85) _1P30[i] = -0.82+0.0011*(i-85); + } + //printf("1P %1.2f %1.2f %1.2f\n",_1P30[44],_1P30[84],_1P30[139]); + + _1P40(maxInd); + _1P40.clear(); + for (int i=0; i5) _1P40[i] = -1.04 +0.00225*(i-5); + else if (i<85 && i>=45) _1P40[i] = -0.95+0.00225*(i-45); + else if (i<140 && i >=85) _1P40[i] = -0.86+0.0015*(i-85); + } + //printf("1P %1.2f %1.2f %1.2f\n",_1P40[44],_1P40[84],_1P40[139]); + + _1P50(maxInd2); + _1P50.clear(); + for (int i=0; i5) _1P50[i] = -1.06 +0.002*(i-5); + else if (i<90 && i>=45) _1P50[i] = -0.98+0.00175*(i-45); + } + //printf("1P %1.2f %1.2f \n",_1P50[44],_1P50[89]); + + _1P60(maxInd2); + _1P60.clear(); + for (int i=0; i5) _1P60[i] = -1.07 +0.0015*(i-5); + else if (i<90 && i>=45) _1P60[i] = -1.01+0.00175*(i-45); + } + //printf("1P %1.2f %1.2f \n",_1P60[44],_1P60[84],_1P60[139]); + + //4P + _4P10(maxInd); + _4P10.clear(); + for (int i=0; i5) _4P10[i] = -0.78 +0.002*(i-5); + else if (i<85 && i>=45) _4P10[i] = -0.7+0.00125*(i-45); + else if (i<140 && i >=85) _4P10[i] = -0.65+0.001*(i-85); + } + //printf("4P %1.2f %1.2f %1.2f\n",_4P10[44],_4P10[84],_4P10[139]); + + _4P20(maxInd); + _4P20.clear(); + for (int i=0; i5) _4P20[i] = -0.84 +0.0025*(i-5); + else if (i<85 && i>=45) _4P20[i] = -0.74+0.00175*(i-45); + else if (i<140 && i >=85) _4P20[i] = -0.67+0.00085*(i-85); + } + //printf("4P %1.2f %1.2f %1.2f\n",_4P20[44],_4P20[84],_4P20[139]); + + _4P30(maxInd); + _4P30.clear(); + for (int i=0; i5) _4P30[i] = -0.85 +0.00225*(i-5); + else if (i<85 && i>=45) _4P30[i] = -0.76+0.00125*(i-45); + else if (i<140 && i >=85) _4P30[i] = -0.71+0.001*(i-85); + } + //printf("4P %1.2f %1.2f %1.2f\n",_4P30[44],_4P30[84],_4P30[139]); + + _4P40(maxInd); + _4P40.clear(); + for (int i=0; i5) _4P40[i] = -0.87 +0.00175*(i-5); + else if (i<85 && i>=45) _4P40[i] = -0.8+0.00175*(i-45); + else if (i<140 && i >=85) _4P40[i] = -0.73+0.00075*(i-85); + } + //printf("4P %1.2f %1.2f %1.2f\n",_4P40[44],_4P40[84],_4P40[139]); + + _4P50(maxInd2); + _4P50.clear(); + for (int i=0; i5) _4P50[i] = -0.88 +0.0015*(i-5); + else if (i<90 && i>=45) _4P50[i] = -0.82+0.0015*(i-45); + } + //printf("4P %1.2f %1.2f \n",_4P50[44],_4P50[89]); + + _4P60(maxInd2); + _4P60.clear(); + for (int i=0; i5) _4P60[i] = -0.89 +0.00125*(i-5); + else if (i<90 && i>=45) _4P60[i] = -0.84+0.00125*(i-45); + } + //printf("4P %1.2f %1.2f\n",_4P60[44],_4P60[89]); + + + //red yellow correction + _10YR20(maxInd2); + _10YR20.clear(); + for (int i=0; i5) _10YR20[i] = 1.22 +0.002*(i-5); + else if (i<90 && i>=45) _10YR20[i] = 1.30+0.006*(i-45); + } + //printf("10YR %1.2f %1.2f\n",_10YR20[44],_10YR20[56]); + _10YR30(maxInd2); + _10YR30.clear(); + for (int i=0; i5) _10YR30[i] = 1.27 +0.00175*(i-5); + else if (i<90 && i>=45) _10YR30[i] = 1.34+0.0017*(i-45); + } + //printf("10YR %1.2f %1.2f\n",_10YR30[44],_10YR30[75]); + _10YR40(maxInd2); + _10YR40.clear(); + for (int i=0; i5) _10YR40[i] = 1.32 +0.00025*(i-5); + else if (i<90 && i>=45) _10YR40[i] = 1.33+0.0015*(i-45); + } + //printf("10YR %1.2f %1.2f\n",_10YR40[44],_10YR40[85]); + _10YR50(maxInd2); + _10YR50.clear(); + for (int i=0; i5) _10YR50[i] = 1.35 +0.000*(i-5); + else if (i<90 && i>=45) _10YR50[i] = 1.35+0.0012*(i-45); + } + //printf("10YR %1.2f %1.2f\n",_10YR50[44],_10YR50[80]); + _10YR60(maxInd); + _10YR60.clear(); + for (int i=0; i5) _10YR60[i] = 1.38 - 0.00025*(i-5); + else if (i<85 && i>=45) _10YR60[i] = 1.37+0.0005*(i-45); + else if (i<140 && i >=85) _10YR60[i] = 1.39+0.0013*(i-85); + } + //printf("10YR %1.2f %1.2f %1.2f\n",_10YR60[44],_10YR60[85],_10YR60[139] ); + _10YR70(maxInd); + _10YR70.clear(); + for (int i=0; i5) _10YR70[i] = 1.41 - 0.0005*(i-5); + else if (i<85 && i>=45) _10YR70[i] = 1.39+0.000*(i-45); + else if (i<140 && i >=85) _10YR70[i] = 1.39+0.0013*(i-85); + } + //printf("10YR %1.2f %1.2f %1.2f\n",_10YR70[44],_10YR70[85],_10YR70[139] ); + _10YR80(maxInd); + _10YR80.clear(); + for (int i=0; i5) _10YR80[i] = 1.45 - 0.00125*(i-5); + else if (i<85 && i>=45) _10YR80[i] = 1.40+0.000*(i-45); + else if (i<140 && i >=85) _10YR80[i] = 1.40+0.00072*(i-85);//1.436 + } + //printf("10YR %1.2f %1.2f %1.2f\n",_10YR80[44],_10YR80[84],_10YR80[139] ); + _10YR90(maxInd2); + _10YR90.clear(); + for (int i=0; i5) _10YR90[i] = 1.48 -0.001*(i-5); + else if (i<90 && i>=45) _10YR90[i] = 1.44-0.0009*(i-45); + } + //printf("10YR %1.2f %1.2f\n",_10YR90[45],_10YR90[80]); + _85YR20(maxInd3); + _85YR20.clear(); + for (int i=0; i5) _85YR20[i] = 1.12 +0.004*(i-5); + } + + //printf("85YR %1.2f \n",_85YR20[44]); + _85YR30(maxInd2); + _85YR30.clear(); + for (int i=0; i5) _85YR30[i] = 1.16 + 0.0025*(i-5); + else if (i<90 && i>=45) _85YR30[i] = 1.26+0.0028*(i-45); + } + //printf("85YR %1.2f %1.2f\n",_85YR30[44],_85YR30[75]); + _85YR40(maxInd2); + _85YR40.clear(); + for (int i=0; i5) _85YR40[i] = 1.20 + 0.0015*(i-5); + else if (i<90 && i>=45) _85YR40[i] = 1.26+0.0024*(i-45); + } + //printf("85YR %1.2f %1.2f\n",_85YR40[44],_85YR40[75]); + _85YR50(maxInd); + _85YR50.clear(); + for (int i=0; i5) _85YR50[i] = 1.24 + 0.0005*(i-5); + else if (i<85 && i>=45) _85YR50[i] = 1.26+0.002*(i-45); + else if (i<140 && i >=85) _85YR50[i] = 1.34+0.0015*(i-85); + } + //printf("85YR %1.2f %1.2f %1.2f\n",_85YR50[44],_85YR50[85],_85YR50[110] ); + _85YR60(maxInd); + _85YR60.clear(); + for (int i=0; i5) _85YR60[i] = 1.27 + 0.00025*(i-5); + else if (i<85 && i>=45) _85YR60[i] = 1.28+0.0015*(i-45); + else if (i<140 && i >=85) _85YR60[i] = 1.34+0.0012*(i-85); + } + //printf("85YR %1.2f %1.2f %1.2f\n",_85YR60[44],_85YR60[85],_85YR60[139] ); + + _85YR70(maxInd); + _85YR70.clear(); + for (int i=0; i5) _85YR70[i] = 1.31 - 0.00025*(i-5); + else if (i<85 && i>=45) _85YR70[i] = 1.30+0.0005*(i-45); + else if (i<140 && i >=85) _85YR70[i] = 1.32+0.0012*(i-85); + } + //printf("85YR %1.2f %1.2f %1.2f\n",_85YR70[44],_85YR70[85],_85YR70[139] ); + _85YR80(maxInd); + _85YR80.clear(); + for (int i=0; i5) _85YR80[i] = 1.35 - 0.00075*(i-5); + else if (i<85 && i>=45) _85YR80[i] = 1.32+0.00025*(i-45); + else if (i<140 && i >=85) _85YR80[i] = 1.33+0.00125*(i-85); + } + //printf("85YR %1.2f %1.2f %1.2f\n",_85YR80[44],_85YR80[85],_85YR80[139] ); + _85YR90(maxInd2); + _85YR90.clear(); + for (int i=0; i5) _85YR90[i] = 1.39 - 0.00125*(i-5); + else if (i<90 && i>=45) _85YR90[i] = 1.34+0.00*(i-45); + } + //printf("85YR %1.2f %1.2f\n",_85YR90[44],_85YR90[85]); + + //7YR + _7YR30(maxInd2); + _7YR30.clear(); + for (int i=0; i5) _7YR30[i] = 1.06 + 0.0028*(i-5); + else if (i<90 && i>=45) _7YR30[i] = 1.17+0.0045*(i-45); + } + //printf("7YR %1.2f %1.2f\n",_7YR30[44],_7YR30[66]); + _7YR40(maxInd2); + _7YR40.clear(); + for (int i=0; i5) _7YR40[i] = 1.10 + 0.0018*(i-5); + else if (i<90 && i>=45) _7YR40[i] = 1.17+0.0035*(i-45); + } + //printf("7YR %1.2f %1.2f\n",_7YR40[44],_7YR40[89]); + _7YR50(maxInd2); + _7YR50.clear(); + for (int i=0; i5) _7YR50[i] = 1.14 + 0.00125*(i-5); + else if (i<90 && i>=45) _7YR50[i] = 1.19+0.002*(i-45); + } + //printf("7YR %1.2f %1.2f\n",_7YR50[44],_7YR50[89] ); + _7YR60(maxInd); + _7YR60.clear(); + for (int i=0; i5) _7YR60[i] = 1.17 + 0.00075*(i-5); + else if (i<85 && i>=45) _7YR60[i] = 1.20+0.00175*(i-45); + else if (i<140 && i >=85) _7YR60[i] = 1.27+0.002*(i-85); + } + //printf("7YR %1.2f %1.2f %1.2f\n",_7YR60[44],_7YR60[84],_7YR60[125] ); + + _7YR70(maxInd); + _7YR70.clear(); + for (int i=0; i5) _7YR70[i] = 1.20 + 0.0005*(i-5); + else if (i<85 && i>=45) _7YR70[i] = 1.22+0.00125*(i-45); + else if (i<140 && i >=85) _7YR70[i] = 1.27+0.0015*(i-85); + } + //printf("7YR %1.2f %1.2f %1.2f\n",_7YR70[44],_7YR70[84],_7YR70[125] ); + _7YR80(maxInd3); + _7YR80.clear(); + for (int i=0; i5) _7YR80[i] = 1.29 - 0.0008*(i-5); + } + //printf("7YR %1.2f \n",_7YR80[44] ); + _55YR30(maxInd3); + _55YR30.clear(); + for (int i=0; i5) _55YR30[i] = 0.96 + 0.0038*(i-5); + } + //printf("55YR %1.2f \n",_55YR30[44] ); + _55YR40(maxInd2); + _55YR40.clear(); + for (int i=0; i5) _55YR40[i] = 1.01 + 0.0022*(i-5); + else if (i<90 && i>=45) _55YR40[i] = 1.10+0.0037*(i-45); + } + //printf("55YR %1.2f %1.2f\n",_55YR40[44],_55YR40[89] ); + _55YR50(maxInd); + _55YR50.clear(); + for (int i=0; i5) _55YR50[i] = 1.06 + 0.0015*(i-5); + else if (i<85 && i>=45) _55YR50[i] = 1.12+0.00225*(i-45); + else if (i<140 && i >=85) _55YR50[i] = 1.21+0.0015*(i-85); + } + //printf("55YR %1.2f %1.2f %1.2f\n",_55YR50[44],_55YR50[84],_55YR50[125] ); + _55YR60(maxInd); + _55YR60.clear(); + for (int i=0; i5) _55YR60[i] = 1.08 + 0.0012*(i-5); + else if (i<85 && i>=45) _55YR60[i] = 1.13+0.0018*(i-45); + else if (i<140 && i >=85) _55YR60[i] = 1.20+0.0025*(i-85); + } + //printf("55YR %1.2f %1.2f %1.2f\n",_55YR60[44],_55YR60[84],_55YR60[125] ); + _55YR70(maxInd); + _55YR70.clear(); + for (int i=0; i5) _55YR70[i] = 1.11 + 0.00075*(i-5); + else if (i<85 && i>=45) _55YR70[i] = 1.14+0.0012*(i-45); + else if (i<140 && i >=85) _55YR70[i] = 1.19+0.00225*(i-85); + } + //printf("55YR %1.2f %1.2f %1.2f\n",_55YR70[44],_55YR70[84],_55YR70[125] ); + _55YR80(maxInd); + _55YR80.clear(); + for (int i=0; i5) _55YR80[i] = 1.16 + 0.00*(i-5); + else if (i<85 && i>=45) _55YR80[i] = 1.16+0.00075*(i-45); + else if (i<140 && i >=85) _55YR80[i] = 1.19+0.00175*(i-85); + } + //printf("55YR %1.2f %1.2f %1.2f\n",_55YR80[44],_55YR80[84],_55YR80[125] ); + _55YR90(maxInd3); + _55YR90.clear(); + for (int i=0; i5) _55YR90[i] = 1.19 - 0.0005*(i-5); + } + //printf("55YR %1.2f \n",_55YR90[44] ); + + _4YR30(maxInd2); + _4YR30.clear(); + for (int i=0; i5) _4YR30[i] = 0.87 + 0.0035*(i-5); + else if (i<90 && i>=45) _4YR30[i] = 1.01+0.0043*(i-45); + } + //printf("4YR %1.2f %1.2f\n",_4YR30[44],_4YR30[78] ); + _4YR40(maxInd2); + _4YR40.clear(); + for (int i=0; i5) _4YR40[i] = 0.92 + 0.0025*(i-5); + else if (i<90 && i>=45) _4YR40[i] = 1.02+0.0033*(i-45); + } + //printf("4YR %1.2f %1.2f\n",_4YR40[44],_4YR40[74] ); + _4YR50(maxInd2); + _4YR50.clear(); + for (int i=0; i5) _4YR50[i] = 0.97 + 0.0015*(i-5); + else if (i<90 && i>=45) _4YR50[i] = 1.03+0.0025*(i-45); + } + //printf("4YR %1.2f %1.2f\n",_4YR50[44],_4YR50[85] ); + _4YR60(maxInd); + _4YR60.clear(); + for (int i=0; i5) _4YR60[i] = 0.99 + 0.00125*(i-5); + else if (i<85 && i>=45) _4YR60[i] = 1.04+0.002*(i-45); + else if (i<140 && i >=85) _4YR60[i] = 1.12+0.003*(i-85); + } + //printf("4YR %1.2f %1.2f %1.2f\n",_4YR60[44],_4YR60[84],_4YR60[125] ); + _4YR70(maxInd); + _4YR70.clear(); + for (int i=0; i5) _4YR70[i] = 1.02 + 0.00075*(i-5); + else if (i<85 && i>=45) _4YR70[i] = 1.05+0.00175*(i-45); + else if (i<140 && i >=85) _4YR70[i] = 1.12+0.002*(i-85); + } + //printf("4YR %1.2f %1.2f %1.2f\n",_4YR70[44],_4YR70[84],_4YR70[125] ); + _4YR80(maxInd3); + _4YR80.clear(); + for (int i=0; i5) _4YR80[i] = 1.09 - 0.0002*(i-5); + } + //printf("4YR %1.2f \n",_4YR80[41] ); + + _25YR30(maxInd2); + _25YR30.clear(); + for (int i=0; i5) _25YR30[i] = 0.77 + 0.004*(i-5); + else if (i<90 && i>=45) _25YR30[i] = 0.94+0.004*(i-45); + } + //printf("25YR %1.2f %1.2f\n",_25YR30[44],_25YR30[74] ); + _25YR40(maxInd2); + _25YR40.clear(); + for (int i=0; i5) _25YR40[i] = 0.82 + 0.003*(i-5); + else if (i<90 && i>=45) _25YR40[i] = 0.94+0.002*(i-45); + } + //printf("25YR %1.2f %1.2f\n",_25YR40[44],_25YR40[84] ); + _25YR50(maxInd2); + _25YR50.clear(); + for (int i=0; i5) _25YR50[i] = 0.87+ 0.002*(i-5); + else if (i<90 && i>=45) _25YR50[i] = 0.95+0.003*(i-45); + } + //printf("25YR %1.2f %1.2f\n",_25YR50[44],_25YR50[84] ); + _25YR60(maxInd2); + _25YR60.clear(); + for (int i=0; i5) _25YR60[i] = 0.89+ 0.0015*(i-5); + else if (i<90 && i>=45) _25YR60[i] = 0.95+0.004*(i-45); + } + //printf("25YR %1.2f %1.2f\n",_25YR60[44],_25YR60[84] ); + _25YR70(maxInd2); + _25YR70.clear(); + for (int i=0; i5) _25YR70[i] = 0.92+ 0.001*(i-5); + else if (i<90 && i>=45) _25YR70[i] = 0.96+0.003*(i-45); + } + //printf("25YR %1.2f %1.2f\n",_25YR70[44],_25YR70[84] ); + + _10R30(maxInd2); + _10R30.clear(); + for (int i=0; i5) _10R30[i] = 0.62 + 0.00225*(i-5); + else if (i<90 && i>=45) _10R30[i] = 0.71+0.003*(i-45); + } + //printf("10R %1.2f %1.2f\n",_10R30[44],_10R30[84] ); + _10R40(maxInd2); + _10R40.clear(); + for (int i=0; i5) _10R40[i] = 0.66 + 0.0025*(i-5); + else if (i<90 && i>=45) _10R40[i] = 0.76+0.0035*(i-45); + } + //printf("10R %1.2f %1.2f\n",_10R40[44],_10R40[84] ); + _10R50(maxInd2); + _10R50.clear(); + for (int i=0; i5) _10R50[i] = 0.71 + 0.002*(i-5); + else if (i<90 && i>=45) _10R50[i] = 0.79+0.0043*(i-45); + } + //printf("10R %1.2f %1.2f\n",_10R50[44],_10R50[84] ); + _10R60(maxInd); + _10R60.clear(); + for (int i=0; i5) _10R60[i] = 0.73 + 0.00175*(i-5); + else if (i<85 && i>=45) _10R60[i] = 0.80 +0.0033*(i-45); + else if (i<140 && i >=85) _10R60[i] = 0.93+0.0018*(i-85); + } + //printf("10R %1.2f %1.2f %1.2f\n",_10R60[44],_10R60[84],_10R60[125] ); + _10R70(maxInd); + _10R70.clear(); + for (int i=0; i5) _10R70[i] = 0.75 + 0.0015*(i-5); + else if (i<85 && i>=45) _10R70[i] = 0.81 +0.0017*(i-45); + else if (i<140 && i >=85) _10R70[i] = 0.88+0.0025*(i-85); + } + //printf("10R %1.2f %1.2f %1.2f\n",_10R70[44],_10R70[84],_10R70[125] ); + + _9R30(maxInd2); + _9R30.clear(); + for (int i=0; i5) _9R30[i] = 0.57 + 0.002*(i-5); + else if (i<90 && i>=45) _9R30[i] = 0.65+0.0018*(i-45); + } + //printf("9R %1.2f %1.2f\n",_9R30[44],_9R30[84] ); + _9R40(maxInd2); + _9R40.clear(); + for (int i=0; i5) _9R40[i] = 0.61 + 0.002*(i-5); + else if (i<90 && i>=45) _9R40[i] = 0.69+0.0025*(i-45); + } + //printf("9R %1.2f %1.2f\n",_9R40[44],_9R40[84] ); + _9R50(maxInd); + _9R50.clear(); + for (int i=0; i5) _9R50[i] = 0.66 + 0.00175*(i-5); + else if (i<85 && i>=45) _9R50[i] = 0.73 +0.0025*(i-45); + else if (i<140 && i >=85) _9R50[i] = 0.83+0.0035*(i-85); + } + //printf("9R %1.2f %1.2f %1.2f\n",_9R50[44],_9R50[84],_9R50[125] ); + _9R60(maxInd); + _9R60.clear(); + for (int i=0; i5) _9R60[i] = 0.68 + 0.0015*(i-5); + else if (i<85 && i>=45) _9R60[i] = 0.74 +0.0022*(i-45); + else if (i<140 && i >=85) _9R60[i] = 0.93+0.0022*(i-85); + } + //printf("9R %1.2f %1.2f %1.2f\n",_9R60[44],_9R60[84],_9R60[125] ); + _9R70(maxInd2); + _9R70.clear(); + for (int i=0; i5) _9R70[i] = 0.70 + 0.0012*(i-5); + else if (i<90 && i>=45) _9R70[i] = 0.75+0.0013*(i-45); + } + //printf("9R %1.2f %1.2f\n",_9R70[44],_9R70[84] ); + + _7R30(maxInd2); + _7R30.clear(); + for (int i=0; i5) _7R30[i] = 0.48 + 0.0015*(i-5); + else if (i<90 && i>=45) _7R30[i] = 0.54-0.0005*(i-45); + } + //printf("7R %1.2f %1.2f\n",_7R30[44],_7R30[84] ); + _7R40(maxInd2); + _7R40.clear(); + for (int i=0; i5) _7R40[i] = 0.51 + 0.0015*(i-5); + else if (i<90 && i>=45) _7R40[i] = 0.57+0.0005*(i-45); + } + //printf("7R %1.2f %1.2f\n",_7R40[44],_7R40[84] ); + _7R50(maxInd); + _7R50.clear(); + for (int i=0; i5) _7R50[i] = 0.54 + 0.0015*(i-5); + else if (i<85 && i>=45) _7R50[i] = 0.60 +0.0005*(i-45); + else if (i<140 && i >=85) _7R50[i] = 0.62+0.0025*(i-85); + } + //printf("7R %1.2f %1.2f %1.2f\n",_7R50[44],_7R50[84],_7R50[125] ); + _7R60(maxInd); + _7R60.clear(); + for (int i=0; i5) _7R60[i] = 0.58 + 0.00075*(i-5); + else if (i<85 && i>=45) _7R60[i] = 0.61 +0.00075*(i-45); + else if (i<140 && i >=85) _7R60[i] = 0.64+0.001*(i-85); + } + //printf("7R %1.2f %1.2f %1.2f\n",_7R60[44],_7R60[84],_7R60[107] ); + _7R70(maxInd2); + _7R70.clear(); + for (int i=0; i5) _7R70[i] = 0.59 + 0.00075*(i-5); + else if (i<90 && i>=45) _7R70[i] = 0.62+0.00075*(i-45); + } + //printf("7R %1.2f %1.2f\n",_7R70[44],_7R70[84] ); + + //5R 1 2 3 + + //5R + _5R10(maxInd2); + _5R10.clear(); + for (int i=0; i5) _5R10[i] = 0.10 - 0.0018*(i-5); + else if (i<90 && i>=45) _5R10[i] = 0.035-0.003*(i-45); + } + //printf("5R %1.2f %1.2f\n",_5R10[44],_5R10[51] ); + _5R20(maxInd2); + _5R20.clear(); + for (int i=0; i5) _5R20[i] = 0.26 - 0.00075*(i-5); + else if (i<90 && i>=45) _5R20[i] = 0.023-0.0002*(i-45); + } + //printf("5R %1.2f %1.2f\n",_5R20[44],_5R20[70] ); + _5R30(maxInd2); + _5R30.clear(); + for (int i=0; i5) _5R30[i] = 0.39 + 0.00075*(i-5); + else if (i<90 && i>=45) _5R30[i] = 0.42-0.0007*(i-45); + } + //printf("5R %1.2f %1.2f\n",_5R30[44],_5R30[85] ); + + //25R + _25R10(maxInd3); + _25R10.clear(); + for (int i=0; i5) _25R10[i] = -0.03 - 0.002*(i-5); + } + //printf("25R %1.2f \n",_25R10[44]); + _25R20(maxInd2); + _25R20.clear(); + for (int i=0; i5) _25R20[i] = 0.13 - 0.0012*(i-5); + else if (i<90 && i>=45) _25R20[i] = 0.08-0.002*(i-45); + } + //printf("25R %1.2f %1.2f\n",_25R20[44],_25R20[69] ); + //25R30: 0.28, 0.26, 0.22 + _25R30(maxInd2); + _25R30.clear(); + for (int i=0; i5) _25R30[i] = 0.28 - 0.0005*(i-5); + else if (i<90 && i>=45) _25R30[i] = 0.26-0.0009*(i-45); + } + //printf("25R %1.2f %1.2f\n",_25R30[44],_25R30[85] ); + + + _10RP10(maxInd3); + _10RP10.clear(); + for (int i=0; i5) _10RP10[i] = -0.16 - 0.0017*(i-5); + } + //printf("10RP %1.2f \n",_10RP10[44]); + _10RP20(maxInd2); + _10RP20.clear(); + for (int i=0; i5) _10RP20[i] = 0.0 - 0.0018*(i-5); + else if (i<90 && i>=45) _10RP20[i] = -0.07-0.0012*(i-45); + } + //printf("10RP %1.2f %1.2f\n",_10RP20[44],_10RP20[69] ); + _10RP30(maxInd2); + _10RP30.clear(); + for (int i=0; i5) _10RP30[i] = 0.15 - 0.001*(i-5); + else if (i<90 && i>=45) _10RP30[i] = 0.11-0.0012*(i-45); + } + //printf("10RP %1.2f %1.2f\n",_10RP30[44],_10RP30[85] ); + + //7G + _7G30(maxInd); + _7G30.clear(); + for (int i=0; i5) _7G30[i] = 2.90 + 0.0027*(i-5); + else if (i<85 && i>=45) _7G30[i] = 3.01+0.0005*(i-45); + else if (i<140 && i >=85) _7G30[i] = 3.03+0.00075*(i-85); + } + //printf("7G %1.2f %1.2f %1.2f\n",_7G30[44],_7G30[84],_7G30[125] ); + _7G40(maxInd); + _7G40.clear(); + for (int i=0; i5) _7G40[i] = 2.89 + 0.00125*(i-5); + else if (i<85 && i>=45) _7G40[i] = 2.94+0.0015*(i-45); + else if (i<140 && i >=85) _7G40[i] = 3.0+0.001*(i-85); + } + //printf("7G %1.2f %1.2f %1.2f\n",_7G40[44],_7G40[84],_7G40[125] ); + _7G50(maxInd); + _7G50.clear(); + for (int i=0; i5) _7G50[i] = 2.87 + 0.0015*(i-5); + else if (i<85 && i>=45) _7G50[i] = 2.93+0.00125*(i-45); + else if (i<140 && i >=85) _7G50[i] = 2.98+0.001*(i-85); + } + //printf("7G %1.2f %1.2f %1.2f\n",_7G50[44],_7G50[84],_7G50[125] ); + _7G60(maxInd); + _7G60.clear(); + for (int i=0; i5) _7G60[i] = 2.86 + 0.00125*(i-5); + else if (i<85 && i>=45) _7G60[i] = 2.91+0.00125*(i-45); + else if (i<140 && i >=85) _7G60[i] = 2.96+0.00075*(i-85); + } + //printf("7G %1.2f %1.2f %1.2f\n",_7G60[44],_7G60[84],_7G60[125] ); + _7G70(maxInd); + _7G70.clear(); + for (int i=0; i5) _7G70[i] = 2.85 + 0.001*(i-5); + else if (i<85 && i>=45) _7G70[i] = 2.89+0.00125*(i-45); + else if (i<140 && i >=85) _7G70[i] = 2.94+0.00075*(i-85); + } + //printf("7G %1.2f %1.2f %1.2f\n",_7G70[44],_7G70[84],_7G70[125] ); + _7G80(maxInd); + _7G80.clear(); + for (int i=0; i5) _7G80[i] = 2.84 + 0.001*(i-5); + else if (i<85 && i>=45) _7G80[i] = 2.88+0.001*(i-45); + else if (i<140 && i >=85) _7G80[i] = 2.92+0.001*(i-85); + } + //printf("7G %1.2f %1.2f %1.2f\n",_7G80[44],_7G80[84],_7G80[125] ); + + + //5G + _5G30(maxInd); + _5G30.clear(); + for (int i=0; i5) _5G30[i] = 2.82 + 0.00175*(i-5); + else if (i<85 && i>=45) _5G30[i] = 2.89+0.0018*(i-45); + else if (i<140 && i >=85) _5G30[i] = 2.96+0.0012*(i-85); + } + //printf("5G %1.2f %1.2f %1.2f\n",_5G30[44],_5G30[84],_5G30[125] ); + _5G40(maxInd); + _5G40.clear(); + for (int i=0; i5) _5G40[i] = 2.80 + 0.0015*(i-5); + else if (i<85 && i>=45) _5G40[i] = 2.86+0.00175*(i-45); + else if (i<140 && i >=85) _5G40[i] = 2.93+0.00125*(i-85); + } + //printf("5G %1.2f %1.2f %1.2f\n",_5G40[44],_5G40[84],_5G40[125] ); + _5G50(maxInd); + _5G50.clear(); + for (int i=0; i5) _5G50[i] = 2.79 + 0.001*(i-5); + else if (i<85 && i>=45) _5G50[i] = 2.84+0.0015*(i-45); + else if (i<140 && i >=85) _5G50[i] = 2.90+0.0015*(i-85); + } + //printf("5G %1.2f %1.2f %1.2f\n",_5G50[44],_5G50[84],_5G50[125] ); + _5G60(maxInd); + _5G60.clear(); + for (int i=0; i5) _5G60[i] = 2.78 + 0.001*(i-5); + else if (i<85 && i>=45) _5G60[i] = 2.82+0.00175*(i-45); + else if (i<140 && i >=85) _5G60[i] = 2.89+0.001*(i-85); + } + //printf("5G %1.2f %1.2f %1.2f\n",_5G60[44],_5G60[84],_5G60[125] ); + _5G70(maxInd); + _5G70.clear(); + for (int i=0; i5) _5G70[i] = 2.77 + 0.001*(i-5); + else if (i<85 && i>=45) _5G70[i] = 2.81+0.00125*(i-45); + else if (i<140 && i >=85) _5G70[i] = 2.86+0.00125*(i-85); + } + //printf("5G %1.2f %1.2f %1.2f\n",_5G70[44],_5G70[84],_5G70[125] ); + _5G80(maxInd); + _5G80.clear(); + for (int i=0; i5) _5G80[i] = 2.76 + 0.001*(i-5); + else if (i<85 && i>=45) _5G80[i] = 2.8+0.00125*(i-45); + else if (i<140 && i >=85) _5G80[i] = 2.85+0.00125*(i-85); + } + //printf("5G %1.2f %1.2f %1.2f\n",_5G80[44],_5G80[84],_5G80[125] ); + + //25G + _25G30(maxInd); + _25G30.clear(); + for (int i=0; i5) _25G30[i] = 2.68 + 0.0015*(i-5); + else if (i<85 && i>=45) _25G30[i] = 2.74+0.0018*(i-45); + else if (i<140 && i >=85) _25G30[i] = 2.81+0.002*(i-85); + } + //printf("25G %1.2f %1.2f %1.2f\n",_25G30[44],_25G30[84],_25G30[125] ); + _25G40(maxInd); + _25G40.clear(); + for (int i=0; i5) _25G40[i] = 2.68 + 0.00075*(i-5); + else if (i<85 && i>=45) _25G40[i] = 2.71+0.0015*(i-45); + else if (i<140 && i >=85) _25G40[i] = 2.77+0.00125*(i-85); + } + //printf("25G %1.2f %1.2f %1.2f\n",_25G40[44],_25G40[84],_25G40[125] ); + _25G50(maxInd); + _25G50.clear(); + for (int i=0; i5) _25G50[i] = 2.65 + 0.00075*(i-5); + else if (i<85 && i>=45) _25G50[i] = 2.68+0.00125*(i-45); + else if (i<140 && i >=85) _25G50[i] = 2.73+0.00125*(i-85); + } + //printf("25G %1.2f %1.2f %1.2f\n",_25G50[44],_25G50[84],_25G50[125] ); + _25G60(maxInd); + _25G60.clear(); + for (int i=0; i5) _25G60[i] = 2.64 + 0.0005*(i-5); + else if (i<85 && i>=45) _25G60[i] = 2.66+0.001*(i-45); + else if (i<140 && i >=85) _25G60[i] = 2.70+0.001*(i-85); + } + //printf("25G %1.2f %1.2f %1.2f\n",_25G60[44],_25G60[84],_25G60[125] ); + _25G70(maxInd); + _25G70.clear(); + for (int i=0; i5) _25G70[i] = 2.64 + 0.00*(i-5); + else if (i<85 && i>=45) _25G70[i] = 2.64+0.00075*(i-45); + else if (i<140 && i >=85) _25G70[i] = 2.67+0.001*(i-85); + } + //printf("25G %1.2f %1.2f %1.2f\n",_25G70[44],_25G70[84],_25G70[125] ); + _25G80(maxInd); + _25G80.clear(); + for (int i=0; i5) _25G80[i] = 2.63 + 0.00*(i-5); + else if (i<85 && i>=45) _25G80[i] = 2.63+0.0005*(i-45); + else if (i<140 && i >=85) _25G80[i] = 2.65+0.0005*(i-85); + } + //printf("25G %1.2f %1.2f %1.2f\n",_25G80[44],_25G80[84],_25G80[125] ); + + + //1G + _1G30(maxInd); + _1G30.clear(); + for (int i=0; i5) _1G30[i] = 2.58 + 0.00025*(i-5); + else if (i<85 && i>=45) _1G30[i] = 2.59+0.001*(i-45); + else if (i<140 && i >=85) _1G30[i] = 2.63+0.00125*(i-85); + } + //printf("1G %1.2f %1.2f %1.2f\n",_1G30[44],_1G30[84],_1G30[125] ); + _1G40(maxInd); + _1G40.clear(); + for (int i=0; i5) _1G40[i] = 2.56 - 0.00025*(i-5); + else if (i<85 && i>=45) _1G40[i] = 2.55+0.0005*(i-45); + else if (i<140 && i >=85) _1G40[i] = 2.57+0.0005*(i-85); + } + //printf("1G %1.2f %1.2f %1.2f\n",_1G40[44],_1G40[84],_1G40[125] ); + _1G50(maxInd); + _1G50.clear(); + for (int i=0; i5) _1G50[i] = 2.55 - 0.00025*(i-5); + else if (i<85 && i>=45) _1G50[i] = 2.54+0.00025*(i-45); + else if (i<140 && i >=85) _1G50[i] = 2.55+0.0005*(i-85); + } + //printf("1G %1.2f %1.2f %1.2f\n",_1G50[44],_1G50[84],_1G50[125] ); + _1G60(maxInd); + _1G60.clear(); + for (int i=0; i5) _1G60[i] = 2.54 - 0.0005*(i-5); + else if (i<85 && i>=45) _1G60[i] = 2.52+0.00025*(i-45); + else if (i<140 && i >=85) _1G60[i] = 2.53+0.00025*(i-85); + } + //printf("1G %1.2f %1.2f %1.2f\n",_1G60[44],_1G60[84],_1G60[125] ); + _1G70(maxInd); + _1G70.clear(); + for (int i=0; i5) _1G70[i] = 2.53 - 0.0005*(i-5); + else if (i<85 && i>=45) _1G70[i] = 2.51+0.0*(i-45); + else if (i<140 && i >=85) _1G70[i] = 2.51+0.00025*(i-85); + } + //printf("1G %1.2f %1.2f %1.2f\n",_1G70[44],_1G70[84],_1G70[125] ); + _1G80(maxInd); + _1G80.clear(); + for (int i=0; i5) _1G80[i] = 2.52 - 0.0005*(i-5); + else if (i<85 && i>=45) _1G80[i] = 2.50+0.00*(i-45); + else if (i<140 && i >=85) _1G80[i] = 2.50+0.00*(i-85); + } + //printf("1G %1.2f %1.2f %1.2f\n",_1G80[44],_1G80[84],_1G80[125] ); + + + //10GY + _10GY30(maxInd); + _10GY30.clear(); + for (int i=0; i5) _10GY30[i] = 2.52 - 0.001*(i-5); + else if (i<85 && i>=45) _10GY30[i] = 2.48-0.002*(i-45); + else if (i<140 && i >=85) _10GY30[i] = 2.40+0.0025*(i-85); + } + //printf("10GY %1.2f %1.2f %1.2f\n",_10GY30[44],_10GY30[84],_10GY30[125] ); + _10GY40(maxInd); + _10GY40.clear(); + for (int i=0; i5) _10GY40[i] = 2.48 - 0.0005*(i-5); + else if (i<85 && i>=45) _10GY40[i] = 2.46-0.0005*(i-45); + else if (i<140 && i >=85) _10GY40[i] = 2.44-0.0015*(i-85); + } + //printf("10GY %1.2f %1.2f %1.2f\n",_10GY40[44],_10GY40[84],_10GY40[125] ); + _10GY50(maxInd); + _10GY50.clear(); + for (int i=0; i5) _10GY50[i] = 2.48 - 0.00075*(i-5); + else if (i<85 && i>=45) _10GY50[i] = 2.45-0.00075*(i-45); + else if (i<140 && i >=85) _10GY50[i] = 2.42-0.00175*(i-85); + } + //printf("10GY %1.2f %1.2f %1.2f\n",_10GY50[44],_10GY50[84],_10GY50[125] ); + _10GY60(maxInd); + _10GY60.clear(); + for (int i=0; i5) _10GY60[i] = 2.47 - 0.00125*(i-5); + else if (i<85 && i>=45) _10GY60[i] = 2.42-0.00025*(i-45); + else if (i<140 && i >=85) _10GY60[i] = 2.41-0.0005*(i-85); + } + //printf("10GY %1.2f %1.2f %1.2f\n",_10GY60[44],_10GY60[84],_10GY60[125] ); + _10GY70(maxInd); + _10GY70.clear(); + for (int i=0; i5) _10GY70[i] = 2.46 - 0.001*(i-5); + else if (i<85 && i>=45) _10GY70[i] = 2.42+0.0*(i-45); + else if (i<140 && i >=85) _10GY70[i] = 2.42-0.001*(i-85); + } + //printf("10GY %1.2f %1.2f %1.2f\n",_10GY70[44],_10GY70[84],_10GY70[125] ); + _10GY80(maxInd); + _10GY80.clear(); + for (int i=0; i5) _10GY80[i] = 2.45 - 0.00075*(i-5); + else if (i<85 && i>=45) _10GY80[i] = 2.42 - 0.0005*(i-45); + else if (i<140 && i >=85) _10GY80[i] = 2.40-0.0005*(i-85); + } + //printf("10GY %1.2f %1.2f %1.2f\n",_10GY80[44],_10GY80[84],_10GY80[125] ); + + + //75GY + _75GY30(maxInd2); + _75GY30.clear(); + for (int i=0; i5) _75GY30[i] = 2.36 - 0.0025*(i-5); + else if (i<90 && i>=45) _75GY30[i] = 2.26-0.00175*(i-45); + } + //printf("75GY %1.2f %1.2f\n",_75GY30[44],_75GY30[84] ); + _75GY40(maxInd2); + _75GY40.clear(); + for (int i=0; i5) _75GY40[i] = 2.34 - 0.00175*(i-5); + else if (i<90 && i>=45) _75GY40[i] = 2.27-0.00225*(i-45); + } + //printf("75GY %1.2f %1.2f \n",_75GY40[44],_75GY40[84] ); + _75GY50(maxInd); + _75GY50.clear(); + for (int i=0; i5) _75GY50[i] = 2.32 - 0.0015*(i-5); + else if (i<85 && i>=45) _75GY50[i] = 2.26-0.00175*(i-45); + else if (i<140 && i >=85) _75GY50[i] = 2.19-0.00325*(i-85); + } + //printf("75GY %1.2f %1.2f %1.2f %1.2f\n",_75GY50[44],_75GY50[84],_75GY50[125],_75GY50[139] ); + _75GY60(maxInd); + _75GY60.clear(); + for (int i=0; i5) _75GY60[i] = 2.30 - 0.00125*(i-5); + else if (i<85 && i>=45) _75GY60[i] = 2.25-0.001*(i-45); + else if (i<140 && i >=85) _75GY60[i] = 2.21-0.0027*(i-85); + } + //printf("75GY %1.2f %1.2f %1.2f\n",_75GY60[44],_75GY60[84],_75GY60[125] ); + _75GY70(maxInd); + _75GY70.clear(); + for (int i=0; i5) _75GY70[i] = 2.29 - 0.00125*(i-5); + else if (i<85 && i>=45) _75GY70[i] = 2.24-0.0015*(i-45); + else if (i<140 && i >=85) _75GY70[i] = 2.18-0.00175*(i-85); + } + //printf("75GY %1.2f %1.2f %1.2f\n",_75GY70[44],_75GY70[84],_75GY70[125] ); + _75GY80(maxInd); + _75GY80.clear(); + for (int i=0; i5) _75GY80[i] = 2.27 - 0.001*(i-5); + else if (i<85 && i>=45) _75GY80[i] = 2.23 - 0.001*(i-45); + else if (i<140 && i >=85) _75GY80[i] = 2.19-0.00175*(i-85); + } + //printf("75GY %1.2f %1.2f %1.2f\n",_75GY80[44],_75GY80[84],_75GY80[125] ); + + + //55GY + _5GY30(maxInd2); + _5GY30.clear(); + for (int i=0; i5) _5GY30[i] = 2.16 - 0.002*(i-5); + else if (i<90 && i>=45) _5GY30[i] = 2.07-0.0025*(i-45); + } + //printf("5GY %1.2f %1.2f\n",_5GY30[44],_5GY30[84] ); + + //5GY4: 2.14,2.04, 1.96, 1.91 //95 + + _5GY40(maxInd2); + _5GY40.clear(); + for (int i=0; i5) _5GY40[i] = 2.14 - 0.0025*(i-5); + else if (i<90 && i>=45) _5GY40[i] = 2.04-0.003*(i-45); + } + //printf("5GY %1.2f %1.2f \n",_5GY40[44],_5GY40[84] ); + _5GY50(maxInd); + _5GY50.clear(); + for (int i=0; i5) _5GY50[i] = 2.13 - 0.00175*(i-5); + else if (i<85 && i>=45) _5GY50[i] = 2.06-0.002*(i-45); + else if (i<140 && i >=85) _5GY50[i] = 1.98-0.00225*(i-85); + } + //printf("5GY %1.2f %1.2f %1.2f\n",_5GY50[44],_5GY50[84],_5GY50[125] ); + _5GY60(maxInd); + _5GY60.clear(); + for (int i=0; i5) _5GY60[i] = 2.11 - 0.0015*(i-5); + else if (i<85 && i>=45) _5GY60[i] = 2.05-0.002*(i-45); + else if (i<140 && i >=85) _5GY60[i] = 1.97-0.00275*(i-85); + } + //printf("5GY %1.2f %1.2f %1.2f\n",_5GY60[44],_5GY60[84],_5GY60[125] ); + _5GY70(maxInd); + _5GY70.clear(); + for (int i=0; i5) _5GY70[i] = 2.09 - 0.001*(i-5); + else if (i<85 && i>=45) _5GY70[i] = 2.05-0.00175*(i-45); + else if (i<140 && i >=85) _5GY70[i] = 1.98-0.002*(i-85); + } + //printf("5GY %1.2f %1.2f %1.2f\n",_5GY70[44],_5GY70[84],_5GY70[125] ); + _5GY80(maxInd); + _5GY80.clear(); + for (int i=0; i5) _5GY80[i] = 2.07 - 0.001*(i-5); + else if (i<85 && i>=45) _5GY80[i] = 2.03 - 0.00075*(i-45); + else if (i<140 && i >=85) _5GY80[i] = 2.0-0.002*(i-85); + } + //printf("5GY %1.2f %1.2f %1.2f\n",_5GY80[44],_5GY80[84],_5GY80[125] ); + + #ifdef _DEBUG + t2e.set(); + if (settings->verbose) + printf("Lutf Munsell %d usec\n", t2e.etime(t1e)); + #endif + } + +} diff --git a/rtengine/color.h b/rtengine/color.h index cae156375..5ccd4e9fe 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -1,1311 +1,1311 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#ifndef _COLOR_H_ -#define _COLOR_H_ - -#include "rt_math.h" -#include "LUT.h" -#include "labimage.h" -#include "iccstore.h" -#include "iccmatrices.h" -#include "sleef.c" -#define SAT(a,b,c) ((float)max(a,b,c)-(float)min(a,b,c))/(float)max(a,b,c) - -namespace rtengine { - -#ifdef _DEBUG - -class MunsellDebugInfo { -public: - float maxdhuelum[4]; - float maxdhue[4]; - unsigned int depass; - unsigned int depassLum; - - MunsellDebugInfo(); - void reinitValues(); -}; - -#endif - -class Color { - -private: - // Jacques' 195 LUTf for Munsell Lch correction - static LUTf _4P10,_4P20,_4P30,_4P40,_4P50,_4P60; - static LUTf _1P10,_1P20,_1P30,_1P40,_1P50,_1P60; - static LUTf _5B40,_5B50,_5B60, _5B70,_5B80; - static LUTf _7B40,_7B50,_7B60, _7B70,_7B80; - static LUTf _9B40,_9B50,_9B60, _9B70,_9B80; - static LUTf _10B40,_10B50,_10B60, _10B70,_10B80; - static LUTf _05PB40,_05PB50,_05PB60, _05PB70,_05PB80; - static LUTf _10PB10,_10PB20,_10PB30,_10PB40,_10PB50,_10PB60; - static LUTf _9PB10,_9PB20,_9PB30,_9PB40,_9PB50,_9PB60,_9PB70,_9PB80; - static LUTf _75PB10,_75PB20,_75PB30,_75PB40,_75PB50,_75PB60,_75PB70,_75PB80; - static LUTf _6PB10,_6PB20,_6PB30,_6PB40,_6PB50,_6PB60,_6PB70,_6PB80; - static LUTf _45PB10,_45PB20,_45PB30,_45PB40,_45PB50,_45PB60,_45PB70,_45PB80; - static LUTf _3PB10,_3PB20,_3PB30,_3PB40,_3PB50,_3PB60,_3PB70,_3PB80; - static LUTf _15PB10,_15PB20,_15PB30,_15PB40,_15PB50,_15PB60, _15PB70,_15PB80; - static LUTf _10YR20, _10YR30, _10YR40,_10YR50,_10YR60,_10YR70,_10YR80,_10YR90; - static LUTf _85YR20, _85YR30, _85YR40,_85YR50,_85YR60,_85YR70,_85YR80,_85YR90; - static LUTf _7YR30, _7YR40,_7YR50,_7YR60,_7YR70,_7YR80; - static LUTf _55YR30, _55YR40,_55YR50,_55YR60,_55YR70,_55YR80,_55YR90; - static LUTf _4YR30, _4YR40,_4YR50,_4YR60,_4YR70,_4YR80; - static LUTf _25YR30, _25YR40,_25YR50,_25YR60,_25YR70; - static LUTf _10R30, _10R40,_10R50,_10R60,_10R70; - static LUTf _9R30, _9R40,_9R50,_9R60,_9R70; - static LUTf _7R30, _7R40,_7R50,_7R60,_7R70; - static LUTf _5R10, _5R20,_5R30; - static LUTf _25R10, _25R20,_25R30; - static LUTf _10RP10, _10RP20,_10RP30; - static LUTf _7G30, _7G40,_7G50,_7G60,_7G70,_7G80; - static LUTf _5G30, _5G40,_5G50,_5G60,_5G70,_5G80; - static LUTf _25G30, _25G40,_25G50,_25G60,_25G70,_25G80; - static LUTf _1G30, _1G40,_1G50,_1G60,_1G70,_1G80; - static LUTf _10GY30, _10GY40,_10GY50,_10GY60,_10GY70,_10GY80; - static LUTf _75GY30, _75GY40,_75GY50,_75GY60,_75GY70,_75GY80; - static LUTf _5GY30, _5GY40,_5GY50,_5GY60,_5GY70,_5GY80; - - // Separated from init() to keep the code clear - static void initMunsell (); - static double hue2rgb(double p, double q, double t); - -public: - - typedef enum Channel { - CHANNEL_RED = 1<<0, - CHANNEL_GREEN = 1<<1, - CHANNEL_BLUE = 1<<2, - CHANNEL_HUE = 1<<3, - CHANNEL_SATURATION = 1<<4, - CHANNEL_VALUE = 1<<5, - CHANNEL_LIGHTNESS = 1<<6, - CHANNEL_CHROMATICITY = 1<<7 - } eChannel; - - typedef enum InterpolationPath { - IP_SHORTEST, /// Interpolate color using the shortest path between 2 hues - IP_LONGEST, /// Interpolate color using the longest path between 2 hues - } eInterpolationPath; - - typedef enum InterpolationDirection { - ID_UP, /// Interpolate color by increasing the hue value, crossing the upper limit - ID_DOWN /// Interpolate color by decreasing the hue value, crossing the lower limit - } eInterpolationDirection; - - const static double sRGBGamma; // standard average gamma - const static double sRGBGammaCurve; // 2.4 in the curve - const static double eps, eps_max, kappa, epskap; - const static float D50x, D50z; - const static double u0, v0; - - static cmsToneCurve* linearGammaTRC; - - static LUTf cachef; - static LUTf gamma2curve; - - // look-up tables for the standard srgb gamma and its inverse (filled by init()) - static LUTf igammatab_srgb; - static LUTf gammatab_srgb; -// static LUTf igammatab_709; -// static LUTf gammatab_709; - static LUTf igammatab_55; - static LUTf gammatab_55; - static LUTf igammatab_4; - static LUTf gammatab_4; - - static LUTf igammatab_26_11; - static LUTf gammatab_26_11; - static LUTf igammatab_24_17; - static LUTf gammatab_24_17a; - static LUTf gammatab_13_2; - - // look-up tables for the simple exponential gamma - static LUTf gammatab; - - - static void init (); - static void cleanup (); - - - /** - * @brief Extract luminance "sRGB" from red/green/blue values - * The range of the r, g and b channel has no importance ([0 ; 1] or [0 ; 65535]...) ; r,g,b can be negatives or > max, but must be in "sRGB" - * @param r red channel - * @param g green channel - * @param b blue channel - * @return luminance value - */ - // xyz_sRGBD65 : conversion matrix from XYZ to sRGB for D65 illuminant: we use diagonal values - static float rgbLuminance(float r, float g, float b) { - // WArning: The sum of xyz_sRGBd65[1][] is > 1.0 (i.e. 1.0000001), so we use our own adapted values) - // 0.2126729, 0.7151521, 0.0721750 - return r*0.2126729f + g*0.7151521f + b*0.0721750f; - } - static double rgbLuminance(double r, double g, double b) { - return r*0.2126729 + g*0.7151521 + b*0.0721750; - } - - - /** - * @brief Convert red/green/blue to hue/saturation/luminance - * @param r red channel [0 ; 65535] - * @param g green channel [0 ; 65535] - * @param b blue channel [0 ; 65535] - * @param h hue channel [0 ; 1] (return value) - * @param s saturation channel [0 ; 1] (return value) - * @param l luminance channel [0; 1] (return value) - */ - static void rgb2hsl (float r, float g, float b, float &h, float &s, float &l); - - - /** - * @brief Convert hue/saturation/luminance in red/green/blue - * @param h hue channel [0 ; 1] - * @param s saturation channel [0 ; 1] - * @param l luminance channel [0 ; 1] - * @param r red channel [0 ; 65535] (return value) - * @param g green channel [0 ; 65535] (return value) - * @param b blue channel [0 ; 65535] (return value) - */ - static void hsl2rgb (float h, float s, float l, float &r, float &g, float &b); - - /** - * @brief Convert hue/saturation/luminance in red/green/blue - * @param h hue channel [0 ; 1] - * @param s saturation channel [0 ; 1] - * @param l luminance channel [0 ; 1] - * @param r red channel [0 ; 1] (return value) - * @param g green channel [0 ; 1] (return value) - * @param b blue channel [0 ; 1] (return value) - */ - static void hsl2rgb01 (float h, float s, float l, float &r, float &g, float &b); - - - /** - * @brief Convert red green blue to hue saturation value - * @param r red channel [0 ; 65535] - * @param g green channel [0 ; 65535] - * @param b blue channel [0 ; 65535] - * @param h hue channel [0 ; 1] (return value) - * @param s saturation channel [0 ; 1] (return value) - * @param v value channel [0 ; 1] (return value) - */ - static void rgb2hsv (float r, float g, float b, float &h, float &s, float &v); - - - /** - * @brief Convert hue saturation value in red green blue - * @param h hue channel [0 ; 1] - * @param s saturation channel [0 ; 1] - * @param v value channel [0 ; 1] - * @param r red channel [0 ; 65535] (return value) - * @param g green channel [0 ; 65535] (return value) - * @param b blue channel [0 ; 65535] (return value) - */ - static void hsv2rgb (float h, float s, float v, float &r, float &g, float &b); - static void hsv2rgb (float h, float s, float v, int &r, int &g, int &b); - - - /** - * @brief Convert hue saturation value in red green blue - * @param h hue channel [0 ; 1] - * @param s saturation channel [0 ; 1] - * @param v value channel [0 ; 1] - * @param r red channel [0 ; 1] (return value) - * @param g green channel [0 ; 1] (return value) - * @param b blue channel [0 ; 1] (return value) - */ - static void hsv2rgb01 (float h, float s, float v, float &r, float &g, float &b); - - - /** - * @brief Convert xyz to red/green/blue - * Color space : sRGB - illuminant D50 - use matrix sRGB_xyz[] - * @param x X coordinate [0 ; 1] or [0 ; 65535] - * @param y Y coordinate [0 ; 1] or [0 ; 65535] - * @param z Z coordinate [0 ; 1] or [0 ; 65535] - * @param r red channel [same range than xyz channel] (return value) - * @param g green channel [same range than xyz channel] (return value) - * @param b blue channel [same range than xyz channel] (return value) - */ - static void xyz2srgb (float x, float y, float z, float &r, float &g, float &b); - - - /** - * @brief Convert xyz to red/green/blue - * Color space : Prophoto - illuminant D50 - use the Prophoto_xyz[] matrix - * @param x X coordinate [0 ; 1] or [0 ; 65535] - * @param y Y coordinate [0 ; 1] or [0 ; 65535] - * @param z Z coordinate [0 ; 1] or [0 ; 65535] - * @param r red channel [same range than xyz channel] (return value) - * @param g green channel [same range than xyz channel] (return value) - * @param b blue channel [same range than xyz channel] (return value) - */ - static void xyz2Prophoto (float x, float y, float z, float &r, float &g, float &b); - - - /** - * @brief Convert rgb in xyz - * Color space : Prophoto - illuminant D50 - use matrix xyz_prophoto[] - * @param r red channel [0 ; 1] or [0 ; 65535] (return value) - * @param g green channel [0 ; 1] or [0 ; 65535] (return value) - * @param b blue channel [0 ; 1] or [0 ; 65535] (return value) - * @param x X coordinate [same range than xyz channel] - * @param y Y coordinate [same range than xyz channel] - * @param z Z coordinate [same range than xyz channel] - */ - static void Prophotoxyz (float r, float g, float b, float &x, float &y, float &z); - - - /** - * @brief Convert xyz in rgb - * Color space : undefined - use adhoc matrix: rgb_xyz[3][3] (iccmatrice.h) in function of working space - * @param x X coordinate [0 ; 1] or [0 ; 65535] - * @param y Y coordinate [0 ; 1] or [0 ; 65535] - * @param z Z coordinate [0 ; 1] or [0 ; 65535] - * @param r red channel [same range than xyz channel] (return value) - * @param g green channel [same range than xyz channel] (return value) - * @param b blue channel [same range than xyz channel] (return value) - * @param rgb_xyz[3][3] transformation matrix to use for the conversion - */ - static void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const double rgb_xyz[3][3]); - static void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const float rgb_xyz[3][3]); - - - /** - * @brief Convert rgb in xyz - * Color space : undefined - use adhoc matrix : xyz_rgb[3][3] (iccmatrice.h) in function of working space - * @param r red channel [0 ; 1] or [0 ; 65535] - * @param g green channel [0 ; 1] or [0 ; 65535] - * @param b blue channel [0 ; 1] or [0 ; 65535] - * @param x X coordinate [same range than rgb channel] (return value) - * @param y Y coordinate [same range than rgb channel] (return value) - * @param z Z coordinate [same range than rgb channel] (return value) - * @param xyz_rgb[3][3] transformation matrix to use for the conversion - */ - static void rgbxyz (float r, float g, float b, float &x, float &y, float &z, const double xyz_rgb[3][3]); - static void rgbxyz (float r, float g, float b, float &x, float &y, float &z, const float xyz_rgb[3][3]); - - - /** - * @brief Convert Lab in xyz - * @param L L channel [0 ; 32768] ; L can be negative rarely or superior 32768 - * @param a channel [-42000 ; +42000] ; can be more than 42000 - * @param b channel [-42000 ; +42000] ; can be more than 42000 - * @param x X coordinate [0 ; 65535] ; can be negative! (return value) - * @param y Y coordinate [0 ; 65535] ; can be negative! (return value) - * @param z Z coordinate [0 ; 65535] ; can be negative! (return value) - */ - static void Lab2XYZ(float L, float a, float b, float &x, float &y, float &z); - -#ifdef __SSE2__ - static void Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat &z); -#endif // __SSE2__ - - /** - * @brief Convert xyz in Lab - * @param x X coordinate [0 ; 65535] ; can be negative or superior to 65535 - * @param y Y coordinate [0 ; 65535] ; can be negative or superior to 65535 - * @param z Z coordinate [0 ; 65535] ; can be negative or superior to 65535 - * @param L L channel [0 ; 32768] ; L can be negative rarely or superior 32768 (return value) - * @param a channel [-42000 ; +42000] ; can be more than 42000 (return value) - * @param b channel [-42000 ; +42000] ; can be more than 42000 (return value) - */ - static void XYZ2Lab(float x, float y, float z, float &L, float &a, float &b); - - - /** - * @brief Convert Lab in Yuv - * @param L L channel [0 ; 32768] ; L can be negative rarely or superior 32768 - * @param a channel [-42000 ; +42000] ; can be more than 42000 - * @param b channel [-42000 ; +42000] ; can be more than 42000 - * @param Y luminance channel [0 ; 65535] (return value) - * @param u red chrominance channel [0 ; 65535] (return value) - * @param v blue chrominance channel [0 ; 65535] (return value) - */ - static void Lab2Yuv(float L, float a, float b, float &Y, float &u, float &v); - - - /** - * @brief Convert Yuv in Lab - * @param Y luminance channel [0 ; 65535] - * @param u red chrominance channel [0 ; 65535] - * @param v blue chrominance channel [0 ; 65535] - * @param L L channel [0 ; 32768] ; L can be negative rarely or superior 32768 (return value) - * @param a channel [-42000 ; +42000] ; can be more than 42000 (return value) - * @param b channel [-42000 ; +42000] ; can be more than 42000 (return value) - */ - static void Yuv2Lab(float Y, float u, float v, float &L, float &a, float &b, double wp[3][3]); - - - /** - * @brief Convert the 'a' and 'b' channels of the L*a*b color space to 'c' and 'h' channels of the Lch color space (channel 'L' is identical [0 ; 32768]) - * @param a 'a' channel [-42000 ; +42000] ; can be more than 42000 - * @param b 'b' channel [-42000 ; +42000] ; can be more than 42000 - * @param c 'c' channel return value, in [0 ; 42000] ; can be more than 42000 (return value) - * @param h 'h' channel return value, in [-PI ; +PI] (return value) - */ - static void Lab2Lch(float a, float b, float &c, float &h); - - - /** - * @brief Convert 'c' and 'h' channels of the Lch color space to the 'a' and 'b' channels of the L*a*b color space (channel 'L' is identical [0 ; 32768]) - * @param c 'c' channel value, in [0 ; 42000] - * @param h 'h' channel value, in [-PI ; +PI] - * @param a 'a' channel [-42000 ; +42000] ; can be more than 42000 (return value) - * @param b 'b' channel [-42000 ; +42000] ; can be more than 42000 (return value) - */ - static void Lch2Lab(float c, float h, float &a, float &b); - - - /** - * @brief Convert the 'u' and 'v' channels of the Luv color space to 'c' and 'h' channels of the Lch color space ('L' channel is identical) - * @param u 'u' channel [unknown range!] - * @param v 'v' channel [unknown range!] - * @param c 'c' channel [unknown range!] (return value) - * @param h 'h' channel [-PI ; +PI] (return value) - */ - static void Luv2Lch(float u, float v, float &c, float &h); - - - /** - * @brief Convert 'c' and 'h' channels of the Lch color space to the 'u' and 'v' channels of the Luv color space ('L' channel is identical) - * @param c 'c' channel [unknown range!] ; can be more than 42000 - * @param h 'h' channel [-PI ; +PI] - * @param u 'u' channel [unknown range!] (return value) - * @param v 'v' channel [unknown range!] (return value) - */ - static void Lch2Luv(float c, float h, float &u, float &v); - - - /** - * @brief Convert the XYZ values to Luv values - * Warning: this method has never been used/tested so far - * @param x X coordinate [0 ; 65535] ; can be negative or superior to 65535 - * @param y Y coordinate [0 ; 65535] ; can be negative or superior to 65535 - * @param z Z coordinate [0 ; 65535] ; can be negative or superior to 65535 - * @param L 'L' channel [0 ; 32768] (return value) - * @param u 'u' channel [-42000 ; 42000] ; can be more than 42000 (return value) - * @param v 'v' channel [-42000 ; 42000] ; can be more than 42000 (return value) - */ - static void XYZ2Luv (float X, float Y, float Z, float &L, float &u, float &v); - - - /** - * @brief Convert the Luv values to XYZ values - * Warning: this method has never been used/tested so far - * @param L 'L' channel [0 ; 32768] - * @param u 'u' channel [-42000 ; 42000] ; can be more than 42000 - * @param v 'v' channel [-42000 ; 42000] ; can be more than 42000 - * @param x X coordinate [0 ; 65535] ; can be negative or superior to 65535 (return value) - * @param y Y coordinate [0 ; 65535] ; can be negative or superior to 65535 (return value) - * @param z Z coordinate [0 ; 65535] ; can be negative or superior to 65535 (return value) - */ - static void Luv2XYZ (float L, float u, float v, float &X, float &Y, float &Z); - - - /** - * @brief Return "f" in function of CIE's kappa and epsilon constants - * @param f f can be fx fy fz where: - * fx=a/500 + fy a=chroma green red [-128 ; +128] - * fy=(L+16)/116 L=luminance [0 ; 100] - * fz=fy-b/200 b=chroma blue yellow [-128 ; +128] - */ - static inline double f2xyz(double f) { - const double epsilonExpInv3 = 6.0/29.0; - const double kappaInv = 27.0/24389.0; // inverse of kappa - - return (f > epsilonExpInv3) ? f*f*f : (116. * f - 16.) * kappaInv; - - } - static inline float f2xyz(float f) { - const float epsilonExpInv3 = 0.20689655f; // 6.0f/29.0f; - const float kappaInv = 0.0011070565f; // 27.0f/24389.0f; // inverse of kappa - - return (f > epsilonExpInv3) ? f*f*f : (116.f * f - 16.f) * kappaInv; - } -#ifdef __SSE2__ - static inline vfloat f2xyz(vfloat f) { - const vfloat epsilonExpInv3 = F2V(0.20689655f); // 6.0f/29.0f; - const vfloat kappaInv = F2V(0.0011070565f); // 27.0f/24389.0f; // inverse of kappa - vfloat res1 = f*f*f; - vfloat res2 = (F2V(116.f) * f - F2V(16.f)) * kappaInv; - return vself(vmaskf_gt(f, epsilonExpInv3), res1, res2); - } -#endif - - /** - * @brief Calculate the effective direction (up or down) to linearly interpolating 2 colors so that it follows the shortest or longest path - * @param h1 First hue [0 ; 1] - * @param h2 Second hue [0 ; 1] - * @param path Path to follow (shortest/longest) - * @return The interpolation direction - */ - static inline eInterpolationDirection getHueInterpolationDirection (double h1, double h2, eInterpolationPath path) { - if (path==IP_SHORTEST) { - if (h2>h1) { - if (h2-h1<=0.5) - return ID_UP; - else - return ID_DOWN; - } - else { - if (h1-h2<=0.5) - return ID_DOWN; - else - return ID_UP; - } - } - else { - if (h2>h1) { - if (h2-h1<=0.5) - return ID_DOWN; - else - return ID_UP; - } - else { - if (h1-h2<=0.5) - return ID_UP; - else - return ID_DOWN; - } - } - } - - - /** - * @brief Calculate a color by linearly interpolating 2 colors - * @param h1 First hue - * @param h2 Second hue - * @param balance Factor from 0 (first hue) to 1 (second hue) - * @param dir Tells which direction the interpolation have to follow. You can get the value with getHueInterpolationDirection - * @return The interpolated hue - */ - static inline double interpolateHueHSV (double h1, double h2, double balance, eInterpolationDirection dir) { - if (h1==h2) - return h1; - if (dir==ID_DOWN) { - if (h1 < h2){ - double temp = h1; - h1 = h2-1.; - h2 = temp; - balance = 1. - balance; - } - double h3 = h1 + balance * (h2-h1); - if (h3<0.) - h3 += 1.; - return h3; - } - else { - if (h1 > h2){ - h2 += 1.; - } - double h3 = h1 + balance * (h2-h1); - if (h3>1.) - h3 -= 1.; - return h3; - } - } - - /** - * @brief Interpolate 2 colors from their respective red/green/blue channels, with a balance factor - * @param balance gives weight to the first and second color [0 ; 1] - * 0. = output color == first color - * 0.5 = output color == equally mixed colors - * 1. = output color == second color - * @param r1 red channel of color 1 [0 ; 65535] - * @param g1 green channel of color 1 [0 ; 65535] - * @param b1 blue channel of color 1 [0 ; 65535] - * @param r2 red channel of color 2 [0 ; 65535] - * @param g2 green channel of color 2 [0 ; 65535] - * @param b2 blue channel of color 2 [0 ; 65535] - * @param channels bitfield of channel to interpolate (CHANNEL_LIGHTNESS|CHANNEL_CHROMATICITY|CHANNEL_HUE) - * @param xyz_rgb color space - * @param ro red channel of output color [0 ; 65535] (return value) - * @param go green channel of output color [0 ; 65535] (return value) - * @param bo blue channel of output color [0 ; 65535] (return value) - */ - static void interpolateRGBColor (const float balance, const float r1, const float g1, const float b1, const float r2, const float g2, const float b2, int channels, const double xyz_rgb[3][3], const double rgb_xyz[3][3], float &ro, float &go, float &bo); - - /** - * @brief Interpolate 2 colors from their respective red/green/blue channels, with a balance factor - * @param realL luminance hsl [0; 1] - * @param iplow low luminance for rl [0;1] - * @param ihigh high luminance for r2 [0;1] - * @param algm algorithm [0;2] - * @param balance gives weight to the first and second color [0 ; 1] - * 0. = output color == first color - * 0.5 = output color == equally mixed colors - * 1. = output color == second color - * @param twoc 2 colors or 512 int - * @param r1 red channel of color 1 [0 ; 65535] - * @param g1 green channel of color 1 [0 ; 65535] - * @param b1 blue channel of color 1 [0 ; 65535] - * @param rl red channel of color low [0 ; 65535] - * @param gl green channel of color low [0 ; 65535] - * @param bl blue channel of color low [0 ; 65535] - - * @param r2 red channel of color 2 or high[0 ; 65535] - * @param g2 green channel of color 2 or high[0 ; 65535] - * @param b2 blue channel of color 2 [or high 0 ; 65535] - * @param channels bitfield of channel to interpolate (CHANNEL_LIGHTNESS|CHANNEL_CHROMATICITY|CHANNEL_HUE) - * @param xyz_rgb color space - * @param rgb_xyz inverse color space - * @param ro red channel of output color [0 ; 65535] (return value) - * @param go green channel of output color [0 ; 65535] (return value) - * @param bo blue channel of output color [0 ; 65535] (return value) - */ - static void interpolateRGBColor (float realL, float iplow, float iphigh, int algm, const float balance, int twoc, int metchrom, bool chr, bool lum, float chromat, float luma, const float r1, const float g1, const float b1, const float xl, const float yl, const float zl, const float x2, const float y2, const float z2, int channels, const double xyz_rgb[3][3], const double rgb_xyz[3][3], float &ro, float &go, float &bo); - - - /** - * @brief Interpolate a hue value as the angle of a polar coordinate with hue in the [0;1] range - * Chose the shorter path from hue 1 to hue 2. - * @param h1 First hue [0; 1] - * @param h2 Second hue [0; 1] - * @param balance Interpolation factor [0 ; 1] where 0.=h1, 1.=h2 - * @return the interpolated value [0;1] - */ - /*template - static inline T interpolatePolarHue_01 (T h1, T h2, U balance) { - - if (h1==h2) - return h1; - if ((h1 > h2) && (h1-h2 > T(0.5))){ - h1 -= T(1.); - double value = h1 + T(balance) * (h2-h1); - if (value < T(0.)) - value += T(1.); - return value; - } - else if (h2-h1 > T(0.5)) { - h2 -= T(1.); - double value = h1 + T(balance) * (h2-h1); - if (value < T(0.)) - value += T(1.); - return value; - } - else - return h1 + T(balance) * (h2-h1); - }*/ - - - /** - * @brief Interpolate a hue value as the angle of a polar coordinate with hue in the [-PI ; +PI] range - * Chose the shorter path from hue 1 to hue 2. - * @param h1 First hue [-PI ; +PI] - * @param h2 Second hue [-PI ; +PI] - * @param balance Interpolation factor [0 ; 1] where 0.=h1, 1.=h2 - * @return the interpolated value [-PI ; +PI] - */ - /*template - static inline T interpolatePolarHue_PI (T h1, T h2, U balance) { - if (h1==h2) - return h1; - if ((h1 > h2) && (h1-h2 > T(M_PI))){ - h1 -= T(2*M_PI); - T value = h1 + T(balance) * (h2-h1); - if (value < T(-M_PI)) - value += T(2*M_PI); - return value; - } - else if (h2-h1 > T(M_PI)) { - h2 -= T(2*M_PI); - T value = h1 + T(balance) * (h2-h1); - if (value < T(0)) - value += T(2*M_PI); - return value; - } - else - return h1 + T(balance) * (h2-h1); - }*/ - - - /** - * @brief Interpolate a hue value as the angle of a polar coordinate with hue in the [0;1] range - * Chose the shorter path from hue 1 to hue 2. - * @param h1 First hue [0; 1] - * @param h2 Second hue [0; 1] - * @param balance Interpolation factor [0 ; 1] where 0.=h1, 1.=h2 - * @return the interpolated value [0;1] - */ - template - static inline T interpolatePolarHue_01 (T h1, T h2, U balance) { - float d = h2 - h1; - float f; - f=T(balance); - double h; - if (h1 > h2){ - std::swap(h1,h2); - d = -d; - f=1.f-f; - } - if (d < T(-M_PI) || d < T(0) || d > T(M_PI)) { //there was an inversion here !! d > T(M_PI) - h1 += T(2*M_PI); - h = h1 + f*(h2-h1); - h = std::fmod(h,2*M_PI); - } - else h = h1 + f * d; - // not strictly necessary..but in case of - if(h < T(-M_PI)) h=T(2*M_PI)-h; - if(h > T(M_PI)) h=h-T(2*M_PI); - - return h; - } - - - /** - * @brief Interpolate a hue value as the angle of a polar coordinate with hue in the [-PI ; +PI] range - * Chose the shorter path from hue 1 to hue 2. - * @param h1 First hue [-PI ; +PI] - * @param h2 Second hue [-PI ; +PI] - * @param balance Interpolation factor [0 ; 1] where 0.=h1, 1.=h2 - * @return the interpolated value [-PI ; +PI ] - */ - template - static inline T interpolatePolarHue_PI (T h1, T h2, U balance) { - float d = h2 - h1; - float f; - f=T(balance); - double h; - if (h1 > h2){ - std::swap(h1,h2); - d = -d; - f=1.f-f; - } - if (d < T(0) || d < T(0.5) || d > T(1.)) { //there was an inversion here !! d > T(M_PI) - h1 += T(1.); - h = h1 + f*(h2-h1); - h = std::fmod(h,1.); - } - else h = h1 + f * d; - // not strictly necessary..but in case of - if(h < T(0)) h=T(1.)-h; - if(h > T(1)) h=h-T(1.); - - return h; - } - - - /** - * @brief Get the gamma curves' parameters used by LCMS2 - * @param pwr gamma value [>1] - * @param ts slope [0 ; 20] - * @param mode [always 0] - * @imax imax [always 0] - * @param gamma0 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) - * @param gamma1 used in ip2Lab2rgb [0 ; 20], can be superior to 20, but it's quite unusual(return value) - * @param gamma2 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) - * @param gamma3 used in ip2Lab2rgb [0 ; 1], usually near 0.003(return value) - * @param gamma4 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) - * @param gamma5 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) - */ - static void calcGamma (double pwr, double ts, int mode, int imax, double &gamma0, double &gamma1, double &gamma2, double &gamma3, double &gamma4,double &gamma5); - - - /** - * @brief Used by Black and White to correct gamma for each channel red, green and blue channel - * @param r red channel input and output value [0 ; 65535] - * @param g green channel input and output value [0 ; 65535] - * @param b blue channel input and output value [0 ; 65535] - * @param gammabwr gamma value for red channel [>0] - * @param gammabwg gamma value for red channel [>0] - * @param gammabwb gamma value for red channel [>0] - */ - static void trcGammaBW (float &r, float &g, float &b, float gammabwr, float gammabwg, float gammabwb); - - - /** @brief Compute the B&W constants for the Black and White processing and its GUI - * @param setting main mode - * @param filter string of the filter effect to use - * @param algo choice between linear and special for OYCPM colors - * @param mixerRed red channel value of the channel mixer [-100 ; +200] - * @param mixerGreen green channel value of the channel mixer [-100 ; +200] - * @param mixerBlue blue channel value of the channel mixer [-100 ; +200] - * @param mixerOrange orange channel value of the channel mixer [-100 ; +200] - * @param mixerYellow yellow channel value of the channel mixer [-100 ; +200] - * @param mixerCyan cyan channel value of the channel mixer [-100 ; +200] - * @param mixerPurple purple channel value of the channel mixer [-100 ; +200] - * @param mixerMagenta magenta channel value of the channel mixer [-100 ; +200] - * @param autoc automatic mode of the channel mixer - * @param complement adjust complementary channel - * @param kcorec in absolute mode, value to correct the mixer [1 ; 3], usually near 1 (return value) - * @param rrm red channel of the mixer (return value) - * @param ggm green channel of the mixer (return value) - * @param bbm blue channel of the mixer (return value) - */ - static void computeBWMixerConstants (const Glib::ustring &setting, const Glib::ustring &filter, const Glib::ustring &algo, float &filcor, float &mixerRed, float &mixerGreen, - float &mixerBlue, float mixerOrange, float mixerYellow, float mixerCyan, float mixerPurple, float mixerMagenta, - bool autoc, bool complement, float &kcorec, double &rrm, double &ggm, double &bbm); - - - // standard srgb gamma and its inverse - - /** - * @brief sRGB gamma - * See also calcGamma above with the following values: pwr=2.4 ts=12.92 mode=0.003041 imax=0.055011 - * @param x red, green or blue channel's value [0 ; 1] - * @return the gamma modified's value [0 ; 1] - */ - static inline double gamma2 (double x) { // g3 1+g4 - return x <= 0.003041 ? x*12.92 : 1.055011*exp(log(x)/sRGBGammaCurve)-0.055011; - } - - - /** - * @brief Inverse sRGB gamma - * See also calcGamma above with the following values: pwr=2.4 ts=12.92 mode=0.003041 imax=0.055011 - * @param x red, green or blue channel's value [0 ; 1] - * @return the inverse gamma modified's value [0 ; 1] - */ - static inline double igamma2 (double x) { //g2 - return x <= 0.039293 ? x/12.92 : exp(log((x+0.055011)/1.055011)*sRGBGammaCurve); - } - - - /** - * @brief Get the gamma value for Gamma=5.5 Slope=10 - * @param x red, green or blue channel's value [0 ; 1] - * @return the gamma modified's value [0 ; 1] - */ - static inline double gamma55 (double x) { // g3 1+g4 - return x <= 0.013189 ? x*10.0 : 1.593503*exp(log(x)/5.5)-0.593503;// 5.5 10 - } - - - /** - * @brief Get the inverse gamma value for Gamma=5.5 Slope=10 - * @param x red, green or blue channel's value [0 ; 1] - * @return the inverse gamma modified's value [0 ; 1] - */ - static inline double igamma55 (double x) { //g2 - return x <= 0.131889 ? x/10.0 : exp(log((x+0.593503)/1.593503)*5.5); // 5.5 10 - } - - - /** - * @brief Get the gamma value for Gamma=4 Slope=5 - * @param x red, green or blue channel's value [0 ; 1] - * @return the gamma modified's value [0 ; 1] - */ - static inline double gamma4 (double x) { // g3 1+g4 - return x <= 0.03089 ? x*5.0 : 1.478793*exp(log(x)/4.1)-0.478793;// 4 5 - } - - - /** - * @brief Get the inverse gamma value for Gamma=4 Slope=5 - * @param x red, green or blue channel's value [0 ; 1] - * @return the inverse gamma modified's value [0 ; 1] - */ - static inline double igamma4 (double x) { //g2 - return x <= 0.154449 ? x/5.0 : exp(log((x+0.478793)/1.478793)*4.1);// 4 5 - } - - - /* - * @brief Get the gamma value for Gamma=2.2 Slope=4.5 - * @param x red, green or blue channel's value [0 ; 1] - * @return the gamma modified's value [0 ; 1] - * - static inline double gamma709 (double x) { - return x <= 0.0176 ? x*4.5 : 1.0954*exp(log(x)/2.2)-0.0954; - } - - * @brief Get the inverse gamma value for Gamma=2.2 Slope=4.5 - * @param x red, green or blue channel's value [0 ; 1] - * @return the inverse gamma modified's value [0 ; 1] - * - static inline double igamma709 (double x) { - return x <= 0.0795 ? x/4.5 : exp(log((x+0.0954)/1.0954)*2.2); - } - */ - - - - /** - * @brief Get the gamma value for Gamma=2.4 Slope=17 - * @param x red, green or blue channel's value [0 ; 1] - * @return the gamma modified's value [0 ; 1] - */ - static inline double gamma24_17 (double x) { - return x <= 0.001867 ? x*17.0 : 1.044445*exp(log(x)/2.4)-0.044445; - } - - - /** - * @brief Get the inverse gamma value for Gamma=2.4 Slope=17 - * @param x red, green or blue channel's value [0 ; 1] - * @return the inverse gamma modified's value [0 ; 1] - */ - static inline double igamma24_17 (double x) { - return x <= 0.031746 ? x/17.0 : exp(log((x+0.044445)/1.044445)*2.4); - } - - - /** - * @brief Get the gamma value for Gamma=2.6 Slope=11 - * @param x red, green or blue channel's value [0 ; 1] - * @return the gamma modified's value [0 ; 1] - */ - static inline double gamma26_11 (double x) { - return x <= 0.004921 ? x*11.0 : 1.086603*exp(log(x)/2.6)-0.086603; - } - - - /** - * @brief Get the inverse gamma value for Gamma=2.6 Slope=11 - * @param x red, green or blue channel's value [0 ; 1] - * @return the inverse gamma modified's value [0 ; 1] - */ - static inline double igamma26_11 (double x) { - return x <= 0.054127 ? x/11.0 : exp(log((x+0.086603)/1.086603)*2.6); - } - /** - * @brief Get the gamma value for Gamma=1.3 Slope=2 - * @param x red, green or blue channel's value [0 ; 1] - * @return the gamma modified's value [0 ; 1] - */ - static inline double gamma13_2 (double x) { - return x <= 0.016613 ? x*2.0 : 1.009968*exp(log(x)/1.3)-0.016613; - } - - - // gamma function with adjustable parameters - //same as above with values calculate with Calcgamma above - // X range 0..1 - static inline double gamma (double x, double gamma, double start, double slope, double mul, double add){ - return (x <= start ? x*slope : exp(log(x)/gamma)*mul-add); - } - static inline double igamma (double x, double gamma, double start, double slope, double mul, double add){ - return (x <= start*slope ? x/slope : exp(log((x+add)/mul)*gamma) ); - } - - - /** - * @brief Very basic gamma - * @param x red, green or blue channel's value [0 ; 1] - * @param gamma gamma value [1 ; 5] - * @return the gamma modified's value [0 ; 1] - */ - static inline double gamman (double x, double gamma) { //standard gamma without slope... - return (x =exp(log(x)/gamma)); - } - - /** - * @brief Very basic gamma - * @param x red, green or blue channel's value [0 ; 1] - * @param gamma gamma value [1 ; 5] - * @return the gamma modified's value [0 ; 1] - */ - static inline float gammanf (float x, float gamma) { //standard gamma without slope... - return (x =xexpf(xlogf(x)/gamma)); - } - - - /** - * @brief Very simply inverse gamma - * @param x red, green or blue channel's value [0 ; 1] - * @param gamma gamma value [1 ; 5] - * @return the inverse gamma modified's value [0 ; 1] - */ - static inline double igamman (double x, double gamma){ //standard inverse gamma without slope... - return (x = exp(log(x)*gamma) ); - } - - - /** - * @brief Get the gamma value out of look-up tables - * Calculated with gamma function above. e.g. : - * for (int i=0; i<65536; i++) - * gammatab_srgb[i] = (65535.0 * gamma2 (i/65535.0)); - * @param x [0 ; 1] - * @return the gamma modified's value [0 ; 65535] - */ - static inline float gamma_srgb (char x) { return gammatab_srgb[x]; } - static inline float gamma (char x) { return gammatab[x]; } - static inline float igamma_srgb (char x) { return igammatab_srgb[x]; } - static inline float gamma_srgb (int x) { return gammatab_srgb[x]; } - static inline float gamma (int x) { return gammatab[x]; } - static inline float igamma_srgb (int x) { return igammatab_srgb[x]; } - static inline float gamma_srgb (float x) { return gammatab_srgb[x]; } - static inline float gamma (float x) { return gammatab[x]; } - static inline float igamma_srgb (float x) { return igammatab_srgb[x]; } - //static inline float gamma_srgb (double x) { return gammatab_srgb[x]; } - //static inline float gamma (double x) { return gammatab[x]; } - //static inline float igamma_srgb (double x) { return igammatab_srgb[x]; } - - - - // -------------------------------- Jacques's Munsell correction - - - /** - * @brief Corrects the color (hue) depending on chromaticity and luminance changes - * - * To use in a "for" or "do while" statement. - * - * @param lumaMuns true => luminance correction (for delta L > 10) and chroma correction ; false => only chroma - * @param Lprov1 luminance after [0 ; 100] - * @param Loldd luminance before [0 ; 100] - * @param HH hue before [-PI ; +PI] - * @param Chprov1 chroma after [0 ; 180 (can be superior)] - * @param CC chroma before [0 ; 180] - * @param corectionHuechroma hue correction depending on chromaticity (saturation), in radians [0 ; 0.45] (return value) - * @param correctlum hue correction depending on luminance (brightness, contrast,...), in radians [0 ; 0.45] (return value) - * @param munsDbgInfo (Debug target only) object to collect informations - */ - -#ifdef _DEBUG - static void AllMunsellLch (bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHueChroma, float &correctlum, MunsellDebugInfo* munsDbgInfo); -#else - static void AllMunsellLch (bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHueChroma, float &correctlum); -#endif - - - /** - * @brief Correct chromaticity and luminance so that the color stays in the working profile's gamut - * - * This function puts the data (Lab) in the gamut of "working profile": - * it returns the corrected values of the chromaticity and luminance - * - * @param HH : hue, in radians [-PI ; +PI] - * @param Lprov1 : input luminance value, sent back corrected [0 ; 100] (input & output value) - * @param Chprov1: input chroma value, sent back corrected [0 ; 180 (can be superior)] (input & output value) - * @param R red value of the corrected color [0 ; 65535 but can be negative or superior to 65535] (return value) - * @param G green value of the corrected color [0 ; 65535 but can be negative or superior to 65535] (return value) - * @param B blue value of the corrected color [0 ; 65535 but can be negative or superior to 65535] (return value) - * @param wip working profile - * @param isHLEnabled true if "Highlight Reconstruction " is enabled - * @param lowerCoef a float number between [0.95 ; 1.0[ - * The nearest it is from 1.0, the more precise it will be, and the longer too as more iteration will be necessary - * @param higherCoef a float number between [0.95 ; 1.0[ - * The nearest it is from 1.0, the more precise it will be, and the longer too as more iteration will be necessary - * @param neg (Debug target only) to calculate iterations for negatives values - * @param moreRGB (Debug target only) to calculate iterations for values >65535 - */ -#ifdef _DEBUG - static void gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb); - static void gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb); - static void gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb); -#else - static void gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef); - static void gamutLchonly (float HH, float2 sincosval,float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef); - static void gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef); -#endif - - - /** - * @brief Munsell gamut correction - * - * This function is the overall Munsell's corrections, but only on global statement. It may be better to use local statement with AllMunsellLch. - * They are named accordingly : gamutLchonly and AllMunsellLch - * It can be used before and after treatment (saturation, gamma, luminance, ...) - * - * @param labL L channel input and output image - * L channel's usual range is [0 ; 100], but values can be negative or >100 - * @param laba a channel input and output image - * @param labb b channel input and output image - * a and b channel's range is usually [-128 ; +128], but values can be >128 - * @param N Number of pixels to process - * @param corMunsell performs Munsell correction - * @param lumaMuns whether to apply luma correction or not (used only if corMuns=true) - * true: apply luma + chroma Munsell correction if delta L > 10; - * false: leaves luma untouched - * @param gamut performs gamutLch - * @param wip matrix for working profile - * @param multiThread whether to parallelize the loop or not - */ - static void LabGamutMunsell (float *labL, float *laba, float *labb, const int N, bool corMunsell, bool lumaMuns, bool isHLEnabled, bool gamut, const double wip[3][3], bool multiThread ); - - - /* - * @brief Skin tone protection factor - * Skin colors: mixed from NX2 skin color palette, Von Luschan, and photos of white, black, yellow people... - * There are some little exceptions, but it should cover 99% case. - * Pay attention to white balance, and do not change hue and saturation, upstream of the modification - * Used by vibrance - * @param lum luma value [0 ; 100] - * @param hue hue value [-PI ; +PI] - * @param chrom chroma value [0 ; 180] - * @param satreduc [0.1 ; 1] (return value) - * @param chromx [0 or 1], actually only 0 is used - */ - static void SkinSat (float lum, float hue, float chrom, float &satreduc);//jacques Skin color - - - /** - * @brief Munsell Lch correction - * Find the right LUT and calculate the correction - * @param lum luma value [0 ; 100] - * @param hue hue value [-PI ; +PI] - * @param chrom chroma value [0 ; 180] - * @param memChprov store chroma [0 ; 180] - * @param correction correction value, in radians [0 ; 0.45] - * @param lbe hue in function of chroma, in radian [-PI ; +PI] - * @param zone [1 ; 4] 1=PB correction + sky 2=red yellow correction 3=Green yellow correction 4=Red purple correction - * @param correctL true=enable the Luminance correction - */ - static void MunsellLch (float lum, float hue, float chrom, float memChprov, float &correction, int zone, float &lbe, bool &correctL);//jacques: Munsell correction - - - // -------------------------------- end Munsell - - - static void scalered ( const float rstprotection, const float param, const float limit, const float HH, const float deltaHH, float &scale, float &scaleext); - static void transitred (const float HH, const float Chprov1, const float dred, const float factorskin, const float protect_red, const float factorskinext, const float deltaHH, const float factorsat, float &factor); - static void skinred ( double J, double h, double sres, double Sp, float dred, float protect_red, int sk, float rstprotection, float ko, double &s); - static void skinredfloat ( float J, float h, float sres, float Sp, float dred, float protect_red, int sk, float rstprotection, float ko, float &s); -// static void scaleredcdbl ( float skinprot, float param, float limit, float HH, float deltaHH, float &scale,float &scaleext); - - static inline void SkinSatCbdl (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r) { - - static const float C9=8.f, C8=15.f, C7=12.f, C4=7.f, C3=5.f, C2=5.f, C1=5.f; - static const float H9=0.05f, H8=0.25f, H7=0.1f, H4=0.02f, H3=0.02f, H2=0.1f, H1=0.1f, H10=-0.2f,H11=-0.2f; - - // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1, uses imolicit factor 1.0 - // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation, uses explicit facor 0.6 - // wide area for transition, uses explicit factor 0.4 - - if (lum >= 85.0f) { - if((hue > (t_l+0.53f-H9) && hue < (t_r+H9)) && (chrom > 8.0f && chrom < (14.0f+C9))) scale = (100.f-skinprot)/100.1f; - else if (lum >= 92.0f) { - if((hue > t_l+0.4f && hue < t_r) && (chrom > 7.0f && chrom < (15.0f))) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > b_l && hue < t_r) && (chrom > 7.0f && chrom < (18.0f))) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if ((hue > t_l+0.4f && hue < t_r-0.3f) && (chrom > 7.0f && chrom < (26.0f+C9))) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > b_l+0.05f && hue < t_r) && (chrom > 7.0f && chrom < (35.0f+C9))) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 70.0f) { - if((hue > t_l+0.15f && hue < (t_r-0.2f+H8)) && (chrom > 8.0f && chrom < (35.0f+C8))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 52.0f) { - if((hue > t_l && hue < (t_r+H7)) && (chrom > 11.0f && chrom < (35.0f+C7))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 35.0f) { - if((hue > t_l && hue < (t_r+H4)) && (chrom > 13.0f && chrom < (37.0f+C4))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 20.0f) { - if((hue > t_l && hue < (t_r+H3)) && (chrom > 7.0f && chrom <(35.0f+C3) )) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 10.0f) { - if((hue > (t_l-0.25f + H10) && hue < (t_r-0.3f +H2)) && (chrom > 8.0f && chrom < (23.0f+C2))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if ((hue > (t_l -0.2f + H10) && hue < (t_r-0.3f+H1)) && (chrom > 8.0f && chrom < (23.0f+C1))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; - - //extended zone for hair, beard and if user adjust high value for skinprot - if(skinprot > 85.f && chrom < 20.f && neg) { - float modula = -0.0666f * skinprot + 6.66f; - scale *= modula; - } - } - - static inline void SkinSatCbdl2 (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r, float b_r, int basc) { - - static const float C9=8.f, C8=15.f, C7=12.f, C4=7.f, C3=5.f, C2=5.f, C1=5.f; - static const float H9=0.05f, H8=0.25f, H7=0.1f, H4=0.02f, H3=0.02f, H2=0.1f, H1=0.1f, H10=-0.2f,H11=-0.2f; - - // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1, uses imolicit factor 1.0 - // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation, uses explicit facor 0.6 - // wide area for transition, uses explicit factor 0.4 - if((b_l > -0.3f && b_r < 2.f) || basc==0) { //range maxi skin - if (lum >= 85.0f) { - if((hue > (t_l+0.53f-H9) && hue < (t_r+H9)) && (chrom > 8.0f && chrom < (14.0f+C9))) scale = (100.f-skinprot)/100.1f; - else if (lum >= 92.0f) { - if((hue > t_l+0.4f && hue < t_r) && (chrom > 7.0f && chrom < (15.0f))) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > b_l && hue < t_r) && (chrom > 7.0f && chrom < (18.0f))) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if ((hue > t_l+0.4f && hue < t_r-0.3f) && (chrom > 7.0f && chrom < (26.0f+C9))) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > b_l+0.05f && hue < t_r) && (chrom > 7.0f && chrom < (35.0f+C9))) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 70.0f) { - if((hue > t_l+0.15f && hue < (t_r-0.2f+H8)) && (chrom > 8.0f && chrom < (35.0f+C8))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 52.0f) { - if((hue > t_l && hue < (t_r+H7)) && (chrom > 11.0f && chrom < (35.0f+C7))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 35.0f) { - if((hue > t_l && hue < (t_r+H4)) && (chrom > 13.0f && chrom < (37.0f+C4))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 20.0f) { - if((hue > t_l && hue < (t_r+H3)) && (chrom > 7.0f && chrom <(35.0f+C3) )) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 10.0f) { - if((hue > (t_l-0.25f + H10) && hue < (t_r-0.3f +H2)) && (chrom > 8.0f && chrom < (23.0f+C2))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if ((hue > (t_l -0.2f + H10) && hue < (t_r-0.3f+H1)) && (chrom > 8.0f && chrom < (23.0f+C1))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; - - //extended zone for hair, beard and if user adjust high value for skinprot - if(skinprot > 85.f && chrom < 20.f && neg) { - float modula = -0.0666f * skinprot + 6.66f; - scale *= modula; - } - } - //end hue skin algo - else if (basc==1) {//not hue skin linear transition or mod chroma curve - if(hue >= t_l && hue <= t_r) scale = (100.f-skinprot)/100.1f; - else if(hue > b_l && hue < t_l) { - float sc=(100.f-skinprot)/100.1f; - float aa=(1.f-sc)/(b_l-t_l); - float bb=1.f-aa*b_l; - scale=aa*hue + bb; - } - else if(hue > t_r && hue < b_r) { - float sc=(100.f-skinprot)/100.1f; - float aa=(sc-1.f)/(t_r-b_r); - float bb=1.f-aa*b_r; - scale=aa*hue + bb; - } - } - } - - - - static inline void SkinSatCbdlCam (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r) { - - static const float C9=8.f, C8=15.f, C7=12.f, C4=7.f, C3=5.f, C2=5.f, C1=5.f; - static const float H9=0.05f, H8=0.25f, H7=0.1f, H4=0.02f, H3=0.02f, H2=0.1f, H1=0.1f, H10=-0.2f,H11=-0.2f; - - float HH = 0.f; - if (hue>8.6f && hue<=74.f ) {HH=(1.15f/65.4f)*hue-0.0012f;} //H > 0.15 H<1.3 - else if(hue>0.f && hue<=8.6f ) {HH=(0.19f/8.6f )*hue-0.04f;} //H>-0.04 H < 0.15 - else if(hue>355.f && hue<=360.f) {HH=(0.11f/5.0f )*hue-7.96f;} //H>-0.15 <-0.04 - else if(hue>74.f && hue<95.f ) {HH=(0.30f/21.0f)*hue+0.24285f;} //H>1.3 H<1.6 - else if(hue>=95.f && hue<137.5f) {HH= 0.01882f*hue-0.18823f;} // H>1.6 H<2.4 - else if(hue>285.f && hue<=355.f) {HH=0.1642f*hue -5.982f;} //HH>-1.3 HH <-0.15 - - hue=HH; - - // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1, uses imolicit factor 1.0 - // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation, uses explicit facor 0.6 - // wide area for transition, uses explicit factor 0.4 - - if (lum >= 85.0f) { - if((hue > (t_l+0.53f-H9) && hue < (t_r+H9)) && (chrom > 8.0f && chrom < (14.0f+C9))) scale = (100.f-skinprot)/100.1f; - else if (lum >= 92.0f) { - if((hue > t_l+0.4f && hue < t_r) && (chrom > 7.0f && chrom < (15.0f))) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > b_l && hue < t_r) && (chrom > 7.0f && chrom < (18.0f))) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if ((hue > t_l+0.4f && hue < t_r-0.3f) && (chrom > 7.0f && chrom < (26.0f+C9))) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > b_l+0.05f && hue < t_r) && (chrom > 7.0f && chrom < (35.0f+C9))) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 70.0f) { - if((hue > t_l+0.15f && hue < (t_r-0.2f+H8)) && (chrom > 8.0f && chrom < (35.0f+C8))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 52.0f) { - if((hue > t_l && hue < (t_r+H7)) && (chrom > 11.0f && chrom < (35.0f+C7))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 35.0f) { - if((hue > t_l && hue < (t_r+H4)) && (chrom > 13.0f && chrom < (37.0f+C4))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 20.0f) { - if((hue > t_l && hue < (t_r+H3)) && (chrom > 7.0f && chrom <(35.0f+C3) )) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if (lum >= 10.0f) { - if((hue > (t_l-0.25f + H10) && hue < (t_r-0.3f +H2)) && (chrom > 8.0f && chrom < (23.0f+C2))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; - } - else if ((hue > (t_l -0.2f + H10) && hue < (t_r-0.3f+H1)) && (chrom > 8.0f && chrom < (23.0f+C1))) scale = (100.f-skinprot)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; - - //extended zone for hair, beard and if user adjust high value for skinprot - if(skinprot > 85.f && chrom < 20.f && neg) { - float modula = -0.0666f * skinprot + 6.66f; - scale *= modula; - } - } - - - /** - * @brief Gamut correction in the XYZ color space - * @param X X channel input value and corrected output value [0 ; 65535] - * @param Y Y channel input value and corrected output value [0 ; 65535] - * @param Z Z channel input value and corrected output value [0 ; 65535] - * @param p working profile - */ - static void gamutmap(float &X, float &Y, float &Z, const double p[3][3]); - - - /** - * @brief Get HSV's hue from the Lab's hue - * @param HH Lab's hue value, in radians [-PI ; +PI] - * @return HSV's hue value [0 ; 1] - */ - static inline double huelab_to_huehsv2 (float HH){ - //hr=translate Hue Lab value (-Pi +Pi) in approximative hr (hsv values) (0 1) [red 1/6 yellow 1/6 green 1/6 cyan 1/6 blue 1/6 magenta 1/6 ] - // with multi linear correspondances (I expect there is no error !!) - double hr = 0.0; - //allways put h between 0 and 1 - - if (HH>=0.f && HH < 0.6f ) hr=0.11666*double(HH) + 0.93; //hr 0.93 1.00 full red - else if (HH>=0.6f && HH < 1.4f ) hr=0.1125 *double(HH) - 0.0675; //hr 0.00 0.09 red yellow orange - else if (HH>=1.4f && HH < 2.f ) hr=0.2666 *double(HH) - 0.2833; //hr 0.09 0.25 orange yellow - else if (HH>=2.f && HH < 3.14159f) hr=0.1489 *double(HH) - 0.04785; //hr 0.25 0.42 yellow green green - else if (HH>=-3.14159f && HH < -2.8f ) hr=0.23419*double(HH) + 1.1557; //hr 0.42 0.50 green - else if (HH>=-2.8f && HH < -2.3f ) hr=0.16 *double(HH) + 0.948; //hr 0.50 0.58 cyan - else if (HH>=-2.3f && HH < -0.9f ) hr=0.12143*double(HH) + 0.85928; //hr 0.58 0.75 blue blue-sky - else if (HH>=-0.9f && HH < -0.1f ) hr=0.2125 *double(HH) + 0.94125; //hr 0.75 0.92 purple magenta - else if (HH>=-0.1f && HH < 0.f ) hr=0.1 *double(HH) + 0.93; //hr 0.92 0.93 red - // in case of ! - if (hr<0.0) hr += 1.0; - else if(hr>1.0) hr -= 1.0; - return (hr); - } - -}; - -} - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#ifndef _COLOR_H_ +#define _COLOR_H_ + +#include "rt_math.h" +#include "LUT.h" +#include "labimage.h" +#include "iccstore.h" +#include "iccmatrices.h" +#include "sleef.c" +#define SAT(a,b,c) ((float)max(a,b,c)-(float)min(a,b,c))/(float)max(a,b,c) + +namespace rtengine { + +#ifdef _DEBUG + +class MunsellDebugInfo { +public: + float maxdhuelum[4]; + float maxdhue[4]; + unsigned int depass; + unsigned int depassLum; + + MunsellDebugInfo(); + void reinitValues(); +}; + +#endif + +class Color { + +private: + // Jacques' 195 LUTf for Munsell Lch correction + static LUTf _4P10,_4P20,_4P30,_4P40,_4P50,_4P60; + static LUTf _1P10,_1P20,_1P30,_1P40,_1P50,_1P60; + static LUTf _5B40,_5B50,_5B60, _5B70,_5B80; + static LUTf _7B40,_7B50,_7B60, _7B70,_7B80; + static LUTf _9B40,_9B50,_9B60, _9B70,_9B80; + static LUTf _10B40,_10B50,_10B60, _10B70,_10B80; + static LUTf _05PB40,_05PB50,_05PB60, _05PB70,_05PB80; + static LUTf _10PB10,_10PB20,_10PB30,_10PB40,_10PB50,_10PB60; + static LUTf _9PB10,_9PB20,_9PB30,_9PB40,_9PB50,_9PB60,_9PB70,_9PB80; + static LUTf _75PB10,_75PB20,_75PB30,_75PB40,_75PB50,_75PB60,_75PB70,_75PB80; + static LUTf _6PB10,_6PB20,_6PB30,_6PB40,_6PB50,_6PB60,_6PB70,_6PB80; + static LUTf _45PB10,_45PB20,_45PB30,_45PB40,_45PB50,_45PB60,_45PB70,_45PB80; + static LUTf _3PB10,_3PB20,_3PB30,_3PB40,_3PB50,_3PB60,_3PB70,_3PB80; + static LUTf _15PB10,_15PB20,_15PB30,_15PB40,_15PB50,_15PB60, _15PB70,_15PB80; + static LUTf _10YR20, _10YR30, _10YR40,_10YR50,_10YR60,_10YR70,_10YR80,_10YR90; + static LUTf _85YR20, _85YR30, _85YR40,_85YR50,_85YR60,_85YR70,_85YR80,_85YR90; + static LUTf _7YR30, _7YR40,_7YR50,_7YR60,_7YR70,_7YR80; + static LUTf _55YR30, _55YR40,_55YR50,_55YR60,_55YR70,_55YR80,_55YR90; + static LUTf _4YR30, _4YR40,_4YR50,_4YR60,_4YR70,_4YR80; + static LUTf _25YR30, _25YR40,_25YR50,_25YR60,_25YR70; + static LUTf _10R30, _10R40,_10R50,_10R60,_10R70; + static LUTf _9R30, _9R40,_9R50,_9R60,_9R70; + static LUTf _7R30, _7R40,_7R50,_7R60,_7R70; + static LUTf _5R10, _5R20,_5R30; + static LUTf _25R10, _25R20,_25R30; + static LUTf _10RP10, _10RP20,_10RP30; + static LUTf _7G30, _7G40,_7G50,_7G60,_7G70,_7G80; + static LUTf _5G30, _5G40,_5G50,_5G60,_5G70,_5G80; + static LUTf _25G30, _25G40,_25G50,_25G60,_25G70,_25G80; + static LUTf _1G30, _1G40,_1G50,_1G60,_1G70,_1G80; + static LUTf _10GY30, _10GY40,_10GY50,_10GY60,_10GY70,_10GY80; + static LUTf _75GY30, _75GY40,_75GY50,_75GY60,_75GY70,_75GY80; + static LUTf _5GY30, _5GY40,_5GY50,_5GY60,_5GY70,_5GY80; + + // Separated from init() to keep the code clear + static void initMunsell (); + static double hue2rgb(double p, double q, double t); + +public: + + typedef enum Channel { + CHANNEL_RED = 1<<0, + CHANNEL_GREEN = 1<<1, + CHANNEL_BLUE = 1<<2, + CHANNEL_HUE = 1<<3, + CHANNEL_SATURATION = 1<<4, + CHANNEL_VALUE = 1<<5, + CHANNEL_LIGHTNESS = 1<<6, + CHANNEL_CHROMATICITY = 1<<7 + } eChannel; + + typedef enum InterpolationPath { + IP_SHORTEST, /// Interpolate color using the shortest path between 2 hues + IP_LONGEST, /// Interpolate color using the longest path between 2 hues + } eInterpolationPath; + + typedef enum InterpolationDirection { + ID_UP, /// Interpolate color by increasing the hue value, crossing the upper limit + ID_DOWN /// Interpolate color by decreasing the hue value, crossing the lower limit + } eInterpolationDirection; + + const static double sRGBGamma; // standard average gamma + const static double sRGBGammaCurve; // 2.4 in the curve + const static double eps, eps_max, kappa, epskap; + const static float D50x, D50z; + const static double u0, v0; + + static cmsToneCurve* linearGammaTRC; + + static LUTf cachef; + static LUTf gamma2curve; + + // look-up tables for the standard srgb gamma and its inverse (filled by init()) + static LUTf igammatab_srgb; + static LUTf gammatab_srgb; +// static LUTf igammatab_709; +// static LUTf gammatab_709; + static LUTf igammatab_55; + static LUTf gammatab_55; + static LUTf igammatab_4; + static LUTf gammatab_4; + + static LUTf igammatab_26_11; + static LUTf gammatab_26_11; + static LUTf igammatab_24_17; + static LUTf gammatab_24_17a; + static LUTf gammatab_13_2; + + // look-up tables for the simple exponential gamma + static LUTf gammatab; + + + static void init (); + static void cleanup (); + + + /** + * @brief Extract luminance "sRGB" from red/green/blue values + * The range of the r, g and b channel has no importance ([0 ; 1] or [0 ; 65535]...) ; r,g,b can be negatives or > max, but must be in "sRGB" + * @param r red channel + * @param g green channel + * @param b blue channel + * @return luminance value + */ + // xyz_sRGBD65 : conversion matrix from XYZ to sRGB for D65 illuminant: we use diagonal values + static float rgbLuminance(float r, float g, float b) { + // WArning: The sum of xyz_sRGBd65[1][] is > 1.0 (i.e. 1.0000001), so we use our own adapted values) + // 0.2126729, 0.7151521, 0.0721750 + return r*0.2126729f + g*0.7151521f + b*0.0721750f; + } + static double rgbLuminance(double r, double g, double b) { + return r*0.2126729 + g*0.7151521 + b*0.0721750; + } + + + /** + * @brief Convert red/green/blue to hue/saturation/luminance + * @param r red channel [0 ; 65535] + * @param g green channel [0 ; 65535] + * @param b blue channel [0 ; 65535] + * @param h hue channel [0 ; 1] (return value) + * @param s saturation channel [0 ; 1] (return value) + * @param l luminance channel [0; 1] (return value) + */ + static void rgb2hsl (float r, float g, float b, float &h, float &s, float &l); + + + /** + * @brief Convert hue/saturation/luminance in red/green/blue + * @param h hue channel [0 ; 1] + * @param s saturation channel [0 ; 1] + * @param l luminance channel [0 ; 1] + * @param r red channel [0 ; 65535] (return value) + * @param g green channel [0 ; 65535] (return value) + * @param b blue channel [0 ; 65535] (return value) + */ + static void hsl2rgb (float h, float s, float l, float &r, float &g, float &b); + + /** + * @brief Convert hue/saturation/luminance in red/green/blue + * @param h hue channel [0 ; 1] + * @param s saturation channel [0 ; 1] + * @param l luminance channel [0 ; 1] + * @param r red channel [0 ; 1] (return value) + * @param g green channel [0 ; 1] (return value) + * @param b blue channel [0 ; 1] (return value) + */ + static void hsl2rgb01 (float h, float s, float l, float &r, float &g, float &b); + + + /** + * @brief Convert red green blue to hue saturation value + * @param r red channel [0 ; 65535] + * @param g green channel [0 ; 65535] + * @param b blue channel [0 ; 65535] + * @param h hue channel [0 ; 1] (return value) + * @param s saturation channel [0 ; 1] (return value) + * @param v value channel [0 ; 1] (return value) + */ + static void rgb2hsv (float r, float g, float b, float &h, float &s, float &v); + + + /** + * @brief Convert hue saturation value in red green blue + * @param h hue channel [0 ; 1] + * @param s saturation channel [0 ; 1] + * @param v value channel [0 ; 1] + * @param r red channel [0 ; 65535] (return value) + * @param g green channel [0 ; 65535] (return value) + * @param b blue channel [0 ; 65535] (return value) + */ + static void hsv2rgb (float h, float s, float v, float &r, float &g, float &b); + static void hsv2rgb (float h, float s, float v, int &r, int &g, int &b); + + + /** + * @brief Convert hue saturation value in red green blue + * @param h hue channel [0 ; 1] + * @param s saturation channel [0 ; 1] + * @param v value channel [0 ; 1] + * @param r red channel [0 ; 1] (return value) + * @param g green channel [0 ; 1] (return value) + * @param b blue channel [0 ; 1] (return value) + */ + static void hsv2rgb01 (float h, float s, float v, float &r, float &g, float &b); + + + /** + * @brief Convert xyz to red/green/blue + * Color space : sRGB - illuminant D50 - use matrix sRGB_xyz[] + * @param x X coordinate [0 ; 1] or [0 ; 65535] + * @param y Y coordinate [0 ; 1] or [0 ; 65535] + * @param z Z coordinate [0 ; 1] or [0 ; 65535] + * @param r red channel [same range than xyz channel] (return value) + * @param g green channel [same range than xyz channel] (return value) + * @param b blue channel [same range than xyz channel] (return value) + */ + static void xyz2srgb (float x, float y, float z, float &r, float &g, float &b); + + + /** + * @brief Convert xyz to red/green/blue + * Color space : Prophoto - illuminant D50 - use the Prophoto_xyz[] matrix + * @param x X coordinate [0 ; 1] or [0 ; 65535] + * @param y Y coordinate [0 ; 1] or [0 ; 65535] + * @param z Z coordinate [0 ; 1] or [0 ; 65535] + * @param r red channel [same range than xyz channel] (return value) + * @param g green channel [same range than xyz channel] (return value) + * @param b blue channel [same range than xyz channel] (return value) + */ + static void xyz2Prophoto (float x, float y, float z, float &r, float &g, float &b); + + + /** + * @brief Convert rgb in xyz + * Color space : Prophoto - illuminant D50 - use matrix xyz_prophoto[] + * @param r red channel [0 ; 1] or [0 ; 65535] (return value) + * @param g green channel [0 ; 1] or [0 ; 65535] (return value) + * @param b blue channel [0 ; 1] or [0 ; 65535] (return value) + * @param x X coordinate [same range than xyz channel] + * @param y Y coordinate [same range than xyz channel] + * @param z Z coordinate [same range than xyz channel] + */ + static void Prophotoxyz (float r, float g, float b, float &x, float &y, float &z); + + + /** + * @brief Convert xyz in rgb + * Color space : undefined - use adhoc matrix: rgb_xyz[3][3] (iccmatrice.h) in function of working space + * @param x X coordinate [0 ; 1] or [0 ; 65535] + * @param y Y coordinate [0 ; 1] or [0 ; 65535] + * @param z Z coordinate [0 ; 1] or [0 ; 65535] + * @param r red channel [same range than xyz channel] (return value) + * @param g green channel [same range than xyz channel] (return value) + * @param b blue channel [same range than xyz channel] (return value) + * @param rgb_xyz[3][3] transformation matrix to use for the conversion + */ + static void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const double rgb_xyz[3][3]); + static void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, const float rgb_xyz[3][3]); + + + /** + * @brief Convert rgb in xyz + * Color space : undefined - use adhoc matrix : xyz_rgb[3][3] (iccmatrice.h) in function of working space + * @param r red channel [0 ; 1] or [0 ; 65535] + * @param g green channel [0 ; 1] or [0 ; 65535] + * @param b blue channel [0 ; 1] or [0 ; 65535] + * @param x X coordinate [same range than rgb channel] (return value) + * @param y Y coordinate [same range than rgb channel] (return value) + * @param z Z coordinate [same range than rgb channel] (return value) + * @param xyz_rgb[3][3] transformation matrix to use for the conversion + */ + static void rgbxyz (float r, float g, float b, float &x, float &y, float &z, const double xyz_rgb[3][3]); + static void rgbxyz (float r, float g, float b, float &x, float &y, float &z, const float xyz_rgb[3][3]); + + + /** + * @brief Convert Lab in xyz + * @param L L channel [0 ; 32768] ; L can be negative rarely or superior 32768 + * @param a channel [-42000 ; +42000] ; can be more than 42000 + * @param b channel [-42000 ; +42000] ; can be more than 42000 + * @param x X coordinate [0 ; 65535] ; can be negative! (return value) + * @param y Y coordinate [0 ; 65535] ; can be negative! (return value) + * @param z Z coordinate [0 ; 65535] ; can be negative! (return value) + */ + static void Lab2XYZ(float L, float a, float b, float &x, float &y, float &z); + +#ifdef __SSE2__ + static void Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat &z); +#endif // __SSE2__ + + /** + * @brief Convert xyz in Lab + * @param x X coordinate [0 ; 65535] ; can be negative or superior to 65535 + * @param y Y coordinate [0 ; 65535] ; can be negative or superior to 65535 + * @param z Z coordinate [0 ; 65535] ; can be negative or superior to 65535 + * @param L L channel [0 ; 32768] ; L can be negative rarely or superior 32768 (return value) + * @param a channel [-42000 ; +42000] ; can be more than 42000 (return value) + * @param b channel [-42000 ; +42000] ; can be more than 42000 (return value) + */ + static void XYZ2Lab(float x, float y, float z, float &L, float &a, float &b); + + + /** + * @brief Convert Lab in Yuv + * @param L L channel [0 ; 32768] ; L can be negative rarely or superior 32768 + * @param a channel [-42000 ; +42000] ; can be more than 42000 + * @param b channel [-42000 ; +42000] ; can be more than 42000 + * @param Y luminance channel [0 ; 65535] (return value) + * @param u red chrominance channel [0 ; 65535] (return value) + * @param v blue chrominance channel [0 ; 65535] (return value) + */ + static void Lab2Yuv(float L, float a, float b, float &Y, float &u, float &v); + + + /** + * @brief Convert Yuv in Lab + * @param Y luminance channel [0 ; 65535] + * @param u red chrominance channel [0 ; 65535] + * @param v blue chrominance channel [0 ; 65535] + * @param L L channel [0 ; 32768] ; L can be negative rarely or superior 32768 (return value) + * @param a channel [-42000 ; +42000] ; can be more than 42000 (return value) + * @param b channel [-42000 ; +42000] ; can be more than 42000 (return value) + */ + static void Yuv2Lab(float Y, float u, float v, float &L, float &a, float &b, double wp[3][3]); + + + /** + * @brief Convert the 'a' and 'b' channels of the L*a*b color space to 'c' and 'h' channels of the Lch color space (channel 'L' is identical [0 ; 32768]) + * @param a 'a' channel [-42000 ; +42000] ; can be more than 42000 + * @param b 'b' channel [-42000 ; +42000] ; can be more than 42000 + * @param c 'c' channel return value, in [0 ; 42000] ; can be more than 42000 (return value) + * @param h 'h' channel return value, in [-PI ; +PI] (return value) + */ + static void Lab2Lch(float a, float b, float &c, float &h); + + + /** + * @brief Convert 'c' and 'h' channels of the Lch color space to the 'a' and 'b' channels of the L*a*b color space (channel 'L' is identical [0 ; 32768]) + * @param c 'c' channel value, in [0 ; 42000] + * @param h 'h' channel value, in [-PI ; +PI] + * @param a 'a' channel [-42000 ; +42000] ; can be more than 42000 (return value) + * @param b 'b' channel [-42000 ; +42000] ; can be more than 42000 (return value) + */ + static void Lch2Lab(float c, float h, float &a, float &b); + + + /** + * @brief Convert the 'u' and 'v' channels of the Luv color space to 'c' and 'h' channels of the Lch color space ('L' channel is identical) + * @param u 'u' channel [unknown range!] + * @param v 'v' channel [unknown range!] + * @param c 'c' channel [unknown range!] (return value) + * @param h 'h' channel [-PI ; +PI] (return value) + */ + static void Luv2Lch(float u, float v, float &c, float &h); + + + /** + * @brief Convert 'c' and 'h' channels of the Lch color space to the 'u' and 'v' channels of the Luv color space ('L' channel is identical) + * @param c 'c' channel [unknown range!] ; can be more than 42000 + * @param h 'h' channel [-PI ; +PI] + * @param u 'u' channel [unknown range!] (return value) + * @param v 'v' channel [unknown range!] (return value) + */ + static void Lch2Luv(float c, float h, float &u, float &v); + + + /** + * @brief Convert the XYZ values to Luv values + * Warning: this method has never been used/tested so far + * @param x X coordinate [0 ; 65535] ; can be negative or superior to 65535 + * @param y Y coordinate [0 ; 65535] ; can be negative or superior to 65535 + * @param z Z coordinate [0 ; 65535] ; can be negative or superior to 65535 + * @param L 'L' channel [0 ; 32768] (return value) + * @param u 'u' channel [-42000 ; 42000] ; can be more than 42000 (return value) + * @param v 'v' channel [-42000 ; 42000] ; can be more than 42000 (return value) + */ + static void XYZ2Luv (float X, float Y, float Z, float &L, float &u, float &v); + + + /** + * @brief Convert the Luv values to XYZ values + * Warning: this method has never been used/tested so far + * @param L 'L' channel [0 ; 32768] + * @param u 'u' channel [-42000 ; 42000] ; can be more than 42000 + * @param v 'v' channel [-42000 ; 42000] ; can be more than 42000 + * @param x X coordinate [0 ; 65535] ; can be negative or superior to 65535 (return value) + * @param y Y coordinate [0 ; 65535] ; can be negative or superior to 65535 (return value) + * @param z Z coordinate [0 ; 65535] ; can be negative or superior to 65535 (return value) + */ + static void Luv2XYZ (float L, float u, float v, float &X, float &Y, float &Z); + + + /** + * @brief Return "f" in function of CIE's kappa and epsilon constants + * @param f f can be fx fy fz where: + * fx=a/500 + fy a=chroma green red [-128 ; +128] + * fy=(L+16)/116 L=luminance [0 ; 100] + * fz=fy-b/200 b=chroma blue yellow [-128 ; +128] + */ + static inline double f2xyz(double f) { + const double epsilonExpInv3 = 6.0/29.0; + const double kappaInv = 27.0/24389.0; // inverse of kappa + + return (f > epsilonExpInv3) ? f*f*f : (116. * f - 16.) * kappaInv; + + } + static inline float f2xyz(float f) { + const float epsilonExpInv3 = 0.20689655f; // 6.0f/29.0f; + const float kappaInv = 0.0011070565f; // 27.0f/24389.0f; // inverse of kappa + + return (f > epsilonExpInv3) ? f*f*f : (116.f * f - 16.f) * kappaInv; + } +#ifdef __SSE2__ + static inline vfloat f2xyz(vfloat f) { + const vfloat epsilonExpInv3 = F2V(0.20689655f); // 6.0f/29.0f; + const vfloat kappaInv = F2V(0.0011070565f); // 27.0f/24389.0f; // inverse of kappa + vfloat res1 = f*f*f; + vfloat res2 = (F2V(116.f) * f - F2V(16.f)) * kappaInv; + return vself(vmaskf_gt(f, epsilonExpInv3), res1, res2); + } +#endif + + /** + * @brief Calculate the effective direction (up or down) to linearly interpolating 2 colors so that it follows the shortest or longest path + * @param h1 First hue [0 ; 1] + * @param h2 Second hue [0 ; 1] + * @param path Path to follow (shortest/longest) + * @return The interpolation direction + */ + static inline eInterpolationDirection getHueInterpolationDirection (double h1, double h2, eInterpolationPath path) { + if (path==IP_SHORTEST) { + if (h2>h1) { + if (h2-h1<=0.5) + return ID_UP; + else + return ID_DOWN; + } + else { + if (h1-h2<=0.5) + return ID_DOWN; + else + return ID_UP; + } + } + else { + if (h2>h1) { + if (h2-h1<=0.5) + return ID_DOWN; + else + return ID_UP; + } + else { + if (h1-h2<=0.5) + return ID_UP; + else + return ID_DOWN; + } + } + } + + + /** + * @brief Calculate a color by linearly interpolating 2 colors + * @param h1 First hue + * @param h2 Second hue + * @param balance Factor from 0 (first hue) to 1 (second hue) + * @param dir Tells which direction the interpolation have to follow. You can get the value with getHueInterpolationDirection + * @return The interpolated hue + */ + static inline double interpolateHueHSV (double h1, double h2, double balance, eInterpolationDirection dir) { + if (h1==h2) + return h1; + if (dir==ID_DOWN) { + if (h1 < h2){ + double temp = h1; + h1 = h2-1.; + h2 = temp; + balance = 1. - balance; + } + double h3 = h1 + balance * (h2-h1); + if (h3<0.) + h3 += 1.; + return h3; + } + else { + if (h1 > h2){ + h2 += 1.; + } + double h3 = h1 + balance * (h2-h1); + if (h3>1.) + h3 -= 1.; + return h3; + } + } + + /** + * @brief Interpolate 2 colors from their respective red/green/blue channels, with a balance factor + * @param balance gives weight to the first and second color [0 ; 1] + * 0. = output color == first color + * 0.5 = output color == equally mixed colors + * 1. = output color == second color + * @param r1 red channel of color 1 [0 ; 65535] + * @param g1 green channel of color 1 [0 ; 65535] + * @param b1 blue channel of color 1 [0 ; 65535] + * @param r2 red channel of color 2 [0 ; 65535] + * @param g2 green channel of color 2 [0 ; 65535] + * @param b2 blue channel of color 2 [0 ; 65535] + * @param channels bitfield of channel to interpolate (CHANNEL_LIGHTNESS|CHANNEL_CHROMATICITY|CHANNEL_HUE) + * @param xyz_rgb color space + * @param ro red channel of output color [0 ; 65535] (return value) + * @param go green channel of output color [0 ; 65535] (return value) + * @param bo blue channel of output color [0 ; 65535] (return value) + */ + static void interpolateRGBColor (const float balance, const float r1, const float g1, const float b1, const float r2, const float g2, const float b2, int channels, const double xyz_rgb[3][3], const double rgb_xyz[3][3], float &ro, float &go, float &bo); + + /** + * @brief Interpolate 2 colors from their respective red/green/blue channels, with a balance factor + * @param realL luminance hsl [0; 1] + * @param iplow low luminance for rl [0;1] + * @param ihigh high luminance for r2 [0;1] + * @param algm algorithm [0;2] + * @param balance gives weight to the first and second color [0 ; 1] + * 0. = output color == first color + * 0.5 = output color == equally mixed colors + * 1. = output color == second color + * @param twoc 2 colors or 512 int + * @param r1 red channel of color 1 [0 ; 65535] + * @param g1 green channel of color 1 [0 ; 65535] + * @param b1 blue channel of color 1 [0 ; 65535] + * @param rl red channel of color low [0 ; 65535] + * @param gl green channel of color low [0 ; 65535] + * @param bl blue channel of color low [0 ; 65535] + + * @param r2 red channel of color 2 or high[0 ; 65535] + * @param g2 green channel of color 2 or high[0 ; 65535] + * @param b2 blue channel of color 2 [or high 0 ; 65535] + * @param channels bitfield of channel to interpolate (CHANNEL_LIGHTNESS|CHANNEL_CHROMATICITY|CHANNEL_HUE) + * @param xyz_rgb color space + * @param rgb_xyz inverse color space + * @param ro red channel of output color [0 ; 65535] (return value) + * @param go green channel of output color [0 ; 65535] (return value) + * @param bo blue channel of output color [0 ; 65535] (return value) + */ + static void interpolateRGBColor (float realL, float iplow, float iphigh, int algm, const float balance, int twoc, int metchrom, bool chr, bool lum, float chromat, float luma, const float r1, const float g1, const float b1, const float xl, const float yl, const float zl, const float x2, const float y2, const float z2, int channels, const double xyz_rgb[3][3], const double rgb_xyz[3][3], float &ro, float &go, float &bo); + + + /** + * @brief Interpolate a hue value as the angle of a polar coordinate with hue in the [0;1] range + * Chose the shorter path from hue 1 to hue 2. + * @param h1 First hue [0; 1] + * @param h2 Second hue [0; 1] + * @param balance Interpolation factor [0 ; 1] where 0.=h1, 1.=h2 + * @return the interpolated value [0;1] + */ + /*template + static inline T interpolatePolarHue_01 (T h1, T h2, U balance) { + + if (h1==h2) + return h1; + if ((h1 > h2) && (h1-h2 > T(0.5))){ + h1 -= T(1.); + double value = h1 + T(balance) * (h2-h1); + if (value < T(0.)) + value += T(1.); + return value; + } + else if (h2-h1 > T(0.5)) { + h2 -= T(1.); + double value = h1 + T(balance) * (h2-h1); + if (value < T(0.)) + value += T(1.); + return value; + } + else + return h1 + T(balance) * (h2-h1); + }*/ + + + /** + * @brief Interpolate a hue value as the angle of a polar coordinate with hue in the [-PI ; +PI] range + * Chose the shorter path from hue 1 to hue 2. + * @param h1 First hue [-PI ; +PI] + * @param h2 Second hue [-PI ; +PI] + * @param balance Interpolation factor [0 ; 1] where 0.=h1, 1.=h2 + * @return the interpolated value [-PI ; +PI] + */ + /*template + static inline T interpolatePolarHue_PI (T h1, T h2, U balance) { + if (h1==h2) + return h1; + if ((h1 > h2) && (h1-h2 > T(M_PI))){ + h1 -= T(2*M_PI); + T value = h1 + T(balance) * (h2-h1); + if (value < T(-M_PI)) + value += T(2*M_PI); + return value; + } + else if (h2-h1 > T(M_PI)) { + h2 -= T(2*M_PI); + T value = h1 + T(balance) * (h2-h1); + if (value < T(0)) + value += T(2*M_PI); + return value; + } + else + return h1 + T(balance) * (h2-h1); + }*/ + + + /** + * @brief Interpolate a hue value as the angle of a polar coordinate with hue in the [0;1] range + * Chose the shorter path from hue 1 to hue 2. + * @param h1 First hue [0; 1] + * @param h2 Second hue [0; 1] + * @param balance Interpolation factor [0 ; 1] where 0.=h1, 1.=h2 + * @return the interpolated value [0;1] + */ + template + static inline T interpolatePolarHue_01 (T h1, T h2, U balance) { + float d = h2 - h1; + float f; + f=T(balance); + double h; + if (h1 > h2){ + std::swap(h1,h2); + d = -d; + f=1.f-f; + } + if (d < T(-M_PI) || d < T(0) || d > T(M_PI)) { //there was an inversion here !! d > T(M_PI) + h1 += T(2*M_PI); + h = h1 + f*(h2-h1); + h = std::fmod(h,2*M_PI); + } + else h = h1 + f * d; + // not strictly necessary..but in case of + if(h < T(-M_PI)) h=T(2*M_PI)-h; + if(h > T(M_PI)) h=h-T(2*M_PI); + + return h; + } + + + /** + * @brief Interpolate a hue value as the angle of a polar coordinate with hue in the [-PI ; +PI] range + * Chose the shorter path from hue 1 to hue 2. + * @param h1 First hue [-PI ; +PI] + * @param h2 Second hue [-PI ; +PI] + * @param balance Interpolation factor [0 ; 1] where 0.=h1, 1.=h2 + * @return the interpolated value [-PI ; +PI ] + */ + template + static inline T interpolatePolarHue_PI (T h1, T h2, U balance) { + float d = h2 - h1; + float f; + f=T(balance); + double h; + if (h1 > h2){ + std::swap(h1,h2); + d = -d; + f=1.f-f; + } + if (d < T(0) || d < T(0.5) || d > T(1.)) { //there was an inversion here !! d > T(M_PI) + h1 += T(1.); + h = h1 + f*(h2-h1); + h = std::fmod(h,1.); + } + else h = h1 + f * d; + // not strictly necessary..but in case of + if(h < T(0)) h=T(1.)-h; + if(h > T(1)) h=h-T(1.); + + return h; + } + + + /** + * @brief Get the gamma curves' parameters used by LCMS2 + * @param pwr gamma value [>1] + * @param ts slope [0 ; 20] + * @param mode [always 0] + * @imax imax [always 0] + * @param gamma0 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) + * @param gamma1 used in ip2Lab2rgb [0 ; 20], can be superior to 20, but it's quite unusual(return value) + * @param gamma2 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) + * @param gamma3 used in ip2Lab2rgb [0 ; 1], usually near 0.003(return value) + * @param gamma4 used in ip2Lab2rgb [0 ; 1], usually near 0.03(return value) + * @param gamma5 used in ip2Lab2rgb [0 ; 1], usually near 0.5 (return value) + */ + static void calcGamma (double pwr, double ts, int mode, int imax, double &gamma0, double &gamma1, double &gamma2, double &gamma3, double &gamma4,double &gamma5); + + + /** + * @brief Used by Black and White to correct gamma for each channel red, green and blue channel + * @param r red channel input and output value [0 ; 65535] + * @param g green channel input and output value [0 ; 65535] + * @param b blue channel input and output value [0 ; 65535] + * @param gammabwr gamma value for red channel [>0] + * @param gammabwg gamma value for red channel [>0] + * @param gammabwb gamma value for red channel [>0] + */ + static void trcGammaBW (float &r, float &g, float &b, float gammabwr, float gammabwg, float gammabwb); + + + /** @brief Compute the B&W constants for the Black and White processing and its GUI + * @param setting main mode + * @param filter string of the filter effect to use + * @param algo choice between linear and special for OYCPM colors + * @param mixerRed red channel value of the channel mixer [-100 ; +200] + * @param mixerGreen green channel value of the channel mixer [-100 ; +200] + * @param mixerBlue blue channel value of the channel mixer [-100 ; +200] + * @param mixerOrange orange channel value of the channel mixer [-100 ; +200] + * @param mixerYellow yellow channel value of the channel mixer [-100 ; +200] + * @param mixerCyan cyan channel value of the channel mixer [-100 ; +200] + * @param mixerPurple purple channel value of the channel mixer [-100 ; +200] + * @param mixerMagenta magenta channel value of the channel mixer [-100 ; +200] + * @param autoc automatic mode of the channel mixer + * @param complement adjust complementary channel + * @param kcorec in absolute mode, value to correct the mixer [1 ; 3], usually near 1 (return value) + * @param rrm red channel of the mixer (return value) + * @param ggm green channel of the mixer (return value) + * @param bbm blue channel of the mixer (return value) + */ + static void computeBWMixerConstants (const Glib::ustring &setting, const Glib::ustring &filter, const Glib::ustring &algo, float &filcor, float &mixerRed, float &mixerGreen, + float &mixerBlue, float mixerOrange, float mixerYellow, float mixerCyan, float mixerPurple, float mixerMagenta, + bool autoc, bool complement, float &kcorec, double &rrm, double &ggm, double &bbm); + + + // standard srgb gamma and its inverse + + /** + * @brief sRGB gamma + * See also calcGamma above with the following values: pwr=2.4 ts=12.92 mode=0.003041 imax=0.055011 + * @param x red, green or blue channel's value [0 ; 1] + * @return the gamma modified's value [0 ; 1] + */ + static inline double gamma2 (double x) { // g3 1+g4 + return x <= 0.003041 ? x*12.92 : 1.055011*exp(log(x)/sRGBGammaCurve)-0.055011; + } + + + /** + * @brief Inverse sRGB gamma + * See also calcGamma above with the following values: pwr=2.4 ts=12.92 mode=0.003041 imax=0.055011 + * @param x red, green or blue channel's value [0 ; 1] + * @return the inverse gamma modified's value [0 ; 1] + */ + static inline double igamma2 (double x) { //g2 + return x <= 0.039293 ? x/12.92 : exp(log((x+0.055011)/1.055011)*sRGBGammaCurve); + } + + + /** + * @brief Get the gamma value for Gamma=5.5 Slope=10 + * @param x red, green or blue channel's value [0 ; 1] + * @return the gamma modified's value [0 ; 1] + */ + static inline double gamma55 (double x) { // g3 1+g4 + return x <= 0.013189 ? x*10.0 : 1.593503*exp(log(x)/5.5)-0.593503;// 5.5 10 + } + + + /** + * @brief Get the inverse gamma value for Gamma=5.5 Slope=10 + * @param x red, green or blue channel's value [0 ; 1] + * @return the inverse gamma modified's value [0 ; 1] + */ + static inline double igamma55 (double x) { //g2 + return x <= 0.131889 ? x/10.0 : exp(log((x+0.593503)/1.593503)*5.5); // 5.5 10 + } + + + /** + * @brief Get the gamma value for Gamma=4 Slope=5 + * @param x red, green or blue channel's value [0 ; 1] + * @return the gamma modified's value [0 ; 1] + */ + static inline double gamma4 (double x) { // g3 1+g4 + return x <= 0.03089 ? x*5.0 : 1.478793*exp(log(x)/4.1)-0.478793;// 4 5 + } + + + /** + * @brief Get the inverse gamma value for Gamma=4 Slope=5 + * @param x red, green or blue channel's value [0 ; 1] + * @return the inverse gamma modified's value [0 ; 1] + */ + static inline double igamma4 (double x) { //g2 + return x <= 0.154449 ? x/5.0 : exp(log((x+0.478793)/1.478793)*4.1);// 4 5 + } + + + /* + * @brief Get the gamma value for Gamma=2.2 Slope=4.5 + * @param x red, green or blue channel's value [0 ; 1] + * @return the gamma modified's value [0 ; 1] + * + static inline double gamma709 (double x) { + return x <= 0.0176 ? x*4.5 : 1.0954*exp(log(x)/2.2)-0.0954; + } + + * @brief Get the inverse gamma value for Gamma=2.2 Slope=4.5 + * @param x red, green or blue channel's value [0 ; 1] + * @return the inverse gamma modified's value [0 ; 1] + * + static inline double igamma709 (double x) { + return x <= 0.0795 ? x/4.5 : exp(log((x+0.0954)/1.0954)*2.2); + } + */ + + + + /** + * @brief Get the gamma value for Gamma=2.4 Slope=17 + * @param x red, green or blue channel's value [0 ; 1] + * @return the gamma modified's value [0 ; 1] + */ + static inline double gamma24_17 (double x) { + return x <= 0.001867 ? x*17.0 : 1.044445*exp(log(x)/2.4)-0.044445; + } + + + /** + * @brief Get the inverse gamma value for Gamma=2.4 Slope=17 + * @param x red, green or blue channel's value [0 ; 1] + * @return the inverse gamma modified's value [0 ; 1] + */ + static inline double igamma24_17 (double x) { + return x <= 0.031746 ? x/17.0 : exp(log((x+0.044445)/1.044445)*2.4); + } + + + /** + * @brief Get the gamma value for Gamma=2.6 Slope=11 + * @param x red, green or blue channel's value [0 ; 1] + * @return the gamma modified's value [0 ; 1] + */ + static inline double gamma26_11 (double x) { + return x <= 0.004921 ? x*11.0 : 1.086603*exp(log(x)/2.6)-0.086603; + } + + + /** + * @brief Get the inverse gamma value for Gamma=2.6 Slope=11 + * @param x red, green or blue channel's value [0 ; 1] + * @return the inverse gamma modified's value [0 ; 1] + */ + static inline double igamma26_11 (double x) { + return x <= 0.054127 ? x/11.0 : exp(log((x+0.086603)/1.086603)*2.6); + } + /** + * @brief Get the gamma value for Gamma=1.3 Slope=2 + * @param x red, green or blue channel's value [0 ; 1] + * @return the gamma modified's value [0 ; 1] + */ + static inline double gamma13_2 (double x) { + return x <= 0.016613 ? x*2.0 : 1.009968*exp(log(x)/1.3)-0.016613; + } + + + // gamma function with adjustable parameters + //same as above with values calculate with Calcgamma above + // X range 0..1 + static inline double gamma (double x, double gamma, double start, double slope, double mul, double add){ + return (x <= start ? x*slope : exp(log(x)/gamma)*mul-add); + } + static inline double igamma (double x, double gamma, double start, double slope, double mul, double add){ + return (x <= start*slope ? x/slope : exp(log((x+add)/mul)*gamma) ); + } + + + /** + * @brief Very basic gamma + * @param x red, green or blue channel's value [0 ; 1] + * @param gamma gamma value [1 ; 5] + * @return the gamma modified's value [0 ; 1] + */ + static inline double gamman (double x, double gamma) { //standard gamma without slope... + return (x =exp(log(x)/gamma)); + } + + /** + * @brief Very basic gamma + * @param x red, green or blue channel's value [0 ; 1] + * @param gamma gamma value [1 ; 5] + * @return the gamma modified's value [0 ; 1] + */ + static inline float gammanf (float x, float gamma) { //standard gamma without slope... + return (x =xexpf(xlogf(x)/gamma)); + } + + + /** + * @brief Very simply inverse gamma + * @param x red, green or blue channel's value [0 ; 1] + * @param gamma gamma value [1 ; 5] + * @return the inverse gamma modified's value [0 ; 1] + */ + static inline double igamman (double x, double gamma){ //standard inverse gamma without slope... + return (x = exp(log(x)*gamma) ); + } + + + /** + * @brief Get the gamma value out of look-up tables + * Calculated with gamma function above. e.g. : + * for (int i=0; i<65536; i++) + * gammatab_srgb[i] = (65535.0 * gamma2 (i/65535.0)); + * @param x [0 ; 1] + * @return the gamma modified's value [0 ; 65535] + */ + static inline float gamma_srgb (char x) { return gammatab_srgb[x]; } + static inline float gamma (char x) { return gammatab[x]; } + static inline float igamma_srgb (char x) { return igammatab_srgb[x]; } + static inline float gamma_srgb (int x) { return gammatab_srgb[x]; } + static inline float gamma (int x) { return gammatab[x]; } + static inline float igamma_srgb (int x) { return igammatab_srgb[x]; } + static inline float gamma_srgb (float x) { return gammatab_srgb[x]; } + static inline float gamma (float x) { return gammatab[x]; } + static inline float igamma_srgb (float x) { return igammatab_srgb[x]; } + //static inline float gamma_srgb (double x) { return gammatab_srgb[x]; } + //static inline float gamma (double x) { return gammatab[x]; } + //static inline float igamma_srgb (double x) { return igammatab_srgb[x]; } + + + + // -------------------------------- Jacques's Munsell correction + + + /** + * @brief Corrects the color (hue) depending on chromaticity and luminance changes + * + * To use in a "for" or "do while" statement. + * + * @param lumaMuns true => luminance correction (for delta L > 10) and chroma correction ; false => only chroma + * @param Lprov1 luminance after [0 ; 100] + * @param Loldd luminance before [0 ; 100] + * @param HH hue before [-PI ; +PI] + * @param Chprov1 chroma after [0 ; 180 (can be superior)] + * @param CC chroma before [0 ; 180] + * @param corectionHuechroma hue correction depending on chromaticity (saturation), in radians [0 ; 0.45] (return value) + * @param correctlum hue correction depending on luminance (brightness, contrast,...), in radians [0 ; 0.45] (return value) + * @param munsDbgInfo (Debug target only) object to collect informations + */ + +#ifdef _DEBUG + static void AllMunsellLch (bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHueChroma, float &correctlum, MunsellDebugInfo* munsDbgInfo); +#else + static void AllMunsellLch (bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHueChroma, float &correctlum); +#endif + + + /** + * @brief Correct chromaticity and luminance so that the color stays in the working profile's gamut + * + * This function puts the data (Lab) in the gamut of "working profile": + * it returns the corrected values of the chromaticity and luminance + * + * @param HH : hue, in radians [-PI ; +PI] + * @param Lprov1 : input luminance value, sent back corrected [0 ; 100] (input & output value) + * @param Chprov1: input chroma value, sent back corrected [0 ; 180 (can be superior)] (input & output value) + * @param R red value of the corrected color [0 ; 65535 but can be negative or superior to 65535] (return value) + * @param G green value of the corrected color [0 ; 65535 but can be negative or superior to 65535] (return value) + * @param B blue value of the corrected color [0 ; 65535 but can be negative or superior to 65535] (return value) + * @param wip working profile + * @param isHLEnabled true if "Highlight Reconstruction " is enabled + * @param lowerCoef a float number between [0.95 ; 1.0[ + * The nearest it is from 1.0, the more precise it will be, and the longer too as more iteration will be necessary + * @param higherCoef a float number between [0.95 ; 1.0[ + * The nearest it is from 1.0, the more precise it will be, and the longer too as more iteration will be necessary + * @param neg (Debug target only) to calculate iterations for negatives values + * @param moreRGB (Debug target only) to calculate iterations for values >65535 + */ +#ifdef _DEBUG + static void gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb); + static void gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb); + static void gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb); +#else + static void gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef); + static void gamutLchonly (float HH, float2 sincosval,float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef); + static void gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef); +#endif + + + /** + * @brief Munsell gamut correction + * + * This function is the overall Munsell's corrections, but only on global statement. It may be better to use local statement with AllMunsellLch. + * They are named accordingly : gamutLchonly and AllMunsellLch + * It can be used before and after treatment (saturation, gamma, luminance, ...) + * + * @param labL L channel input and output image + * L channel's usual range is [0 ; 100], but values can be negative or >100 + * @param laba a channel input and output image + * @param labb b channel input and output image + * a and b channel's range is usually [-128 ; +128], but values can be >128 + * @param N Number of pixels to process + * @param corMunsell performs Munsell correction + * @param lumaMuns whether to apply luma correction or not (used only if corMuns=true) + * true: apply luma + chroma Munsell correction if delta L > 10; + * false: leaves luma untouched + * @param gamut performs gamutLch + * @param wip matrix for working profile + * @param multiThread whether to parallelize the loop or not + */ + static void LabGamutMunsell (float *labL, float *laba, float *labb, const int N, bool corMunsell, bool lumaMuns, bool isHLEnabled, bool gamut, const double wip[3][3], bool multiThread ); + + + /* + * @brief Skin tone protection factor + * Skin colors: mixed from NX2 skin color palette, Von Luschan, and photos of white, black, yellow people... + * There are some little exceptions, but it should cover 99% case. + * Pay attention to white balance, and do not change hue and saturation, upstream of the modification + * Used by vibrance + * @param lum luma value [0 ; 100] + * @param hue hue value [-PI ; +PI] + * @param chrom chroma value [0 ; 180] + * @param satreduc [0.1 ; 1] (return value) + * @param chromx [0 or 1], actually only 0 is used + */ + static void SkinSat (float lum, float hue, float chrom, float &satreduc);//jacques Skin color + + + /** + * @brief Munsell Lch correction + * Find the right LUT and calculate the correction + * @param lum luma value [0 ; 100] + * @param hue hue value [-PI ; +PI] + * @param chrom chroma value [0 ; 180] + * @param memChprov store chroma [0 ; 180] + * @param correction correction value, in radians [0 ; 0.45] + * @param lbe hue in function of chroma, in radian [-PI ; +PI] + * @param zone [1 ; 4] 1=PB correction + sky 2=red yellow correction 3=Green yellow correction 4=Red purple correction + * @param correctL true=enable the Luminance correction + */ + static void MunsellLch (float lum, float hue, float chrom, float memChprov, float &correction, int zone, float &lbe, bool &correctL);//jacques: Munsell correction + + + // -------------------------------- end Munsell + + + static void scalered ( const float rstprotection, const float param, const float limit, const float HH, const float deltaHH, float &scale, float &scaleext); + static void transitred (const float HH, const float Chprov1, const float dred, const float factorskin, const float protect_red, const float factorskinext, const float deltaHH, const float factorsat, float &factor); + static void skinred ( double J, double h, double sres, double Sp, float dred, float protect_red, int sk, float rstprotection, float ko, double &s); + static void skinredfloat ( float J, float h, float sres, float Sp, float dred, float protect_red, int sk, float rstprotection, float ko, float &s); +// static void scaleredcdbl ( float skinprot, float param, float limit, float HH, float deltaHH, float &scale,float &scaleext); + + static inline void SkinSatCbdl (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r) { + + static const float C9=8.f, C8=15.f, C7=12.f, C4=7.f, C3=5.f, C2=5.f, C1=5.f; + static const float H9=0.05f, H8=0.25f, H7=0.1f, H4=0.02f, H3=0.02f, H2=0.1f, H1=0.1f, H10=-0.2f,H11=-0.2f; + + // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1, uses imolicit factor 1.0 + // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation, uses explicit facor 0.6 + // wide area for transition, uses explicit factor 0.4 + + if (lum >= 85.0f) { + if((hue > (t_l+0.53f-H9) && hue < (t_r+H9)) && (chrom > 8.0f && chrom < (14.0f+C9))) scale = (100.f-skinprot)/100.1f; + else if (lum >= 92.0f) { + if((hue > t_l+0.4f && hue < t_r) && (chrom > 7.0f && chrom < (15.0f))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l && hue < t_r) && (chrom > 7.0f && chrom < (18.0f))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > t_l+0.4f && hue < t_r-0.3f) && (chrom > 7.0f && chrom < (26.0f+C9))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l+0.05f && hue < t_r) && (chrom > 7.0f && chrom < (35.0f+C9))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 70.0f) { + if((hue > t_l+0.15f && hue < (t_r-0.2f+H8)) && (chrom > 8.0f && chrom < (35.0f+C8))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 52.0f) { + if((hue > t_l && hue < (t_r+H7)) && (chrom > 11.0f && chrom < (35.0f+C7))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 35.0f) { + if((hue > t_l && hue < (t_r+H4)) && (chrom > 13.0f && chrom < (37.0f+C4))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 20.0f) { + if((hue > t_l && hue < (t_r+H3)) && (chrom > 7.0f && chrom <(35.0f+C3) )) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 10.0f) { + if((hue > (t_l-0.25f + H10) && hue < (t_r-0.3f +H2)) && (chrom > 8.0f && chrom < (23.0f+C2))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > (t_l -0.2f + H10) && hue < (t_r-0.3f+H1)) && (chrom > 8.0f && chrom < (23.0f+C1))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + + //extended zone for hair, beard and if user adjust high value for skinprot + if(skinprot > 85.f && chrom < 20.f && neg) { + float modula = -0.0666f * skinprot + 6.66f; + scale *= modula; + } + } + + static inline void SkinSatCbdl2 (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r, float b_r, int basc) { + + static const float C9=8.f, C8=15.f, C7=12.f, C4=7.f, C3=5.f, C2=5.f, C1=5.f; + static const float H9=0.05f, H8=0.25f, H7=0.1f, H4=0.02f, H3=0.02f, H2=0.1f, H1=0.1f, H10=-0.2f,H11=-0.2f; + + // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1, uses imolicit factor 1.0 + // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation, uses explicit facor 0.6 + // wide area for transition, uses explicit factor 0.4 + if((b_l > -0.3f && b_r < 2.f) || basc==0) { //range maxi skin + if (lum >= 85.0f) { + if((hue > (t_l+0.53f-H9) && hue < (t_r+H9)) && (chrom > 8.0f && chrom < (14.0f+C9))) scale = (100.f-skinprot)/100.1f; + else if (lum >= 92.0f) { + if((hue > t_l+0.4f && hue < t_r) && (chrom > 7.0f && chrom < (15.0f))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l && hue < t_r) && (chrom > 7.0f && chrom < (18.0f))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > t_l+0.4f && hue < t_r-0.3f) && (chrom > 7.0f && chrom < (26.0f+C9))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l+0.05f && hue < t_r) && (chrom > 7.0f && chrom < (35.0f+C9))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 70.0f) { + if((hue > t_l+0.15f && hue < (t_r-0.2f+H8)) && (chrom > 8.0f && chrom < (35.0f+C8))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 52.0f) { + if((hue > t_l && hue < (t_r+H7)) && (chrom > 11.0f && chrom < (35.0f+C7))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 35.0f) { + if((hue > t_l && hue < (t_r+H4)) && (chrom > 13.0f && chrom < (37.0f+C4))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 20.0f) { + if((hue > t_l && hue < (t_r+H3)) && (chrom > 7.0f && chrom <(35.0f+C3) )) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 10.0f) { + if((hue > (t_l-0.25f + H10) && hue < (t_r-0.3f +H2)) && (chrom > 8.0f && chrom < (23.0f+C2))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > (t_l -0.2f + H10) && hue < (t_r-0.3f+H1)) && (chrom > 8.0f && chrom < (23.0f+C1))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + + //extended zone for hair, beard and if user adjust high value for skinprot + if(skinprot > 85.f && chrom < 20.f && neg) { + float modula = -0.0666f * skinprot + 6.66f; + scale *= modula; + } + } + //end hue skin algo + else if (basc==1) {//not hue skin linear transition or mod chroma curve + if(hue >= t_l && hue <= t_r) scale = (100.f-skinprot)/100.1f; + else if(hue > b_l && hue < t_l) { + float sc=(100.f-skinprot)/100.1f; + float aa=(1.f-sc)/(b_l-t_l); + float bb=1.f-aa*b_l; + scale=aa*hue + bb; + } + else if(hue > t_r && hue < b_r) { + float sc=(100.f-skinprot)/100.1f; + float aa=(sc-1.f)/(t_r-b_r); + float bb=1.f-aa*b_r; + scale=aa*hue + bb; + } + } + } + + + + static inline void SkinSatCbdlCam (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r) { + + static const float C9=8.f, C8=15.f, C7=12.f, C4=7.f, C3=5.f, C2=5.f, C1=5.f; + static const float H9=0.05f, H8=0.25f, H7=0.1f, H4=0.02f, H3=0.02f, H2=0.1f, H1=0.1f, H10=-0.2f,H11=-0.2f; + + float HH = 0.f; + if (hue>8.6f && hue<=74.f ) {HH=(1.15f/65.4f)*hue-0.0012f;} //H > 0.15 H<1.3 + else if(hue>0.f && hue<=8.6f ) {HH=(0.19f/8.6f )*hue-0.04f;} //H>-0.04 H < 0.15 + else if(hue>355.f && hue<=360.f) {HH=(0.11f/5.0f )*hue-7.96f;} //H>-0.15 <-0.04 + else if(hue>74.f && hue<95.f ) {HH=(0.30f/21.0f)*hue+0.24285f;} //H>1.3 H<1.6 + else if(hue>=95.f && hue<137.5f) {HH= 0.01882f*hue-0.18823f;} // H>1.6 H<2.4 + else if(hue>285.f && hue<=355.f) {HH=0.1642f*hue -5.982f;} //HH>-1.3 HH <-0.15 + + hue=HH; + + // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1, uses imolicit factor 1.0 + // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation, uses explicit facor 0.6 + // wide area for transition, uses explicit factor 0.4 + + if (lum >= 85.0f) { + if((hue > (t_l+0.53f-H9) && hue < (t_r+H9)) && (chrom > 8.0f && chrom < (14.0f+C9))) scale = (100.f-skinprot)/100.1f; + else if (lum >= 92.0f) { + if((hue > t_l+0.4f && hue < t_r) && (chrom > 7.0f && chrom < (15.0f))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l && hue < t_r) && (chrom > 7.0f && chrom < (18.0f))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > t_l+0.4f && hue < t_r-0.3f) && (chrom > 7.0f && chrom < (26.0f+C9))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l+0.05f && hue < t_r) && (chrom > 7.0f && chrom < (35.0f+C9))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 70.0f) { + if((hue > t_l+0.15f && hue < (t_r-0.2f+H8)) && (chrom > 8.0f && chrom < (35.0f+C8))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 52.0f) { + if((hue > t_l && hue < (t_r+H7)) && (chrom > 11.0f && chrom < (35.0f+C7))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 35.0f) { + if((hue > t_l && hue < (t_r+H4)) && (chrom > 13.0f && chrom < (37.0f+C4))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 20.0f) { + if((hue > t_l && hue < (t_r+H3)) && (chrom > 7.0f && chrom <(35.0f+C3) )) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 10.0f) { + if((hue > (t_l-0.25f + H10) && hue < (t_r-0.3f +H2)) && (chrom > 8.0f && chrom < (23.0f+C2))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > (t_l -0.2f + H10) && hue < (t_r-0.3f+H1)) && (chrom > 8.0f && chrom < (23.0f+C1))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + + //extended zone for hair, beard and if user adjust high value for skinprot + if(skinprot > 85.f && chrom < 20.f && neg) { + float modula = -0.0666f * skinprot + 6.66f; + scale *= modula; + } + } + + + /** + * @brief Gamut correction in the XYZ color space + * @param X X channel input value and corrected output value [0 ; 65535] + * @param Y Y channel input value and corrected output value [0 ; 65535] + * @param Z Z channel input value and corrected output value [0 ; 65535] + * @param p working profile + */ + static void gamutmap(float &X, float &Y, float &Z, const double p[3][3]); + + + /** + * @brief Get HSV's hue from the Lab's hue + * @param HH Lab's hue value, in radians [-PI ; +PI] + * @return HSV's hue value [0 ; 1] + */ + static inline double huelab_to_huehsv2 (float HH){ + //hr=translate Hue Lab value (-Pi +Pi) in approximative hr (hsv values) (0 1) [red 1/6 yellow 1/6 green 1/6 cyan 1/6 blue 1/6 magenta 1/6 ] + // with multi linear correspondances (I expect there is no error !!) + double hr = 0.0; + //allways put h between 0 and 1 + + if (HH>=0.f && HH < 0.6f ) hr=0.11666*double(HH) + 0.93; //hr 0.93 1.00 full red + else if (HH>=0.6f && HH < 1.4f ) hr=0.1125 *double(HH) - 0.0675; //hr 0.00 0.09 red yellow orange + else if (HH>=1.4f && HH < 2.f ) hr=0.2666 *double(HH) - 0.2833; //hr 0.09 0.25 orange yellow + else if (HH>=2.f && HH < 3.14159f) hr=0.1489 *double(HH) - 0.04785; //hr 0.25 0.42 yellow green green + else if (HH>=-3.14159f && HH < -2.8f ) hr=0.23419*double(HH) + 1.1557; //hr 0.42 0.50 green + else if (HH>=-2.8f && HH < -2.3f ) hr=0.16 *double(HH) + 0.948; //hr 0.50 0.58 cyan + else if (HH>=-2.3f && HH < -0.9f ) hr=0.12143*double(HH) + 0.85928; //hr 0.58 0.75 blue blue-sky + else if (HH>=-0.9f && HH < -0.1f ) hr=0.2125 *double(HH) + 0.94125; //hr 0.75 0.92 purple magenta + else if (HH>=-0.1f && HH < 0.f ) hr=0.1 *double(HH) + 0.93; //hr 0.92 0.93 red + // in case of ! + if (hr<0.0) hr += 1.0; + else if(hr>1.0) hr -= 1.0; + return (hr); + } + +}; + +} + +#endif diff --git a/rtengine/cplx_wavelet_dec.cc b/rtengine/cplx_wavelet_dec.cc index 4a35cd371..44812d428 100644 --- a/rtengine/cplx_wavelet_dec.cc +++ b/rtengine/cplx_wavelet_dec.cc @@ -1,38 +1,38 @@ -/* - * This file is part of RawTherapee. - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - * - * 2010 Ilya Popov - * 2012 Emil Martinec - */ - -#include "cplx_wavelet_dec.h" - -namespace rtengine { - - wavelet_decomposition::~wavelet_decomposition() - { - for(int i = 0; i <= lvltot; i++) { - if(wavelet_decomp[i] != NULL) - delete wavelet_decomp[i]; - } - delete[] wavfilt_anal; - delete[] wavfilt_synth; - if(coeff0) - delete [] coeff0; - } - -}; - +/* + * This file is part of RawTherapee. + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * 2010 Ilya Popov + * 2012 Emil Martinec + */ + +#include "cplx_wavelet_dec.h" + +namespace rtengine { + + wavelet_decomposition::~wavelet_decomposition() + { + for(int i = 0; i <= lvltot; i++) { + if(wavelet_decomp[i] != NULL) + delete wavelet_decomp[i]; + } + delete[] wavfilt_anal; + delete[] wavfilt_synth; + if(coeff0) + delete [] coeff0; + } + +}; + diff --git a/rtengine/cplx_wavelet_dec.h b/rtengine/cplx_wavelet_dec.h index b178adc2a..1f7732afe 100644 --- a/rtengine/cplx_wavelet_dec.h +++ b/rtengine/cplx_wavelet_dec.h @@ -1,245 +1,245 @@ -/* - * This file is part of RawTherapee. - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - * - * 2010 Ilya Popov - * 2012 Emil Martinec - */ - -#ifndef CPLX_WAVELET_DEC_H_INCLUDED -#define CPLX_WAVELET_DEC_H_INCLUDED - -#include -#include - -#include "cplx_wavelet_level.h" -#include "cplx_wavelet_filter_coeffs.h" - -namespace rtengine { - - class wavelet_decomposition - { - public: - - typedef float internal_type; - float *coeff0; - bool memoryAllocationFailed; - - private: - - static const int maxlevels = 10;//should be greater than any conceivable order of decimation - - int lvltot, subsamp; - int numThreads; - int m_w, m_h;//dimensions - - int wavfilt_len, wavfilt_offset; - float *wavfilt_anal; - float *wavfilt_synth; - - - wavelet_level * wavelet_decomp[maxlevels]; - - public: - - template - wavelet_decomposition(E * src, int width, int height, int maxlvl, int subsampling, int skipcrop = 1, int numThreads = 1, int Daub4Len = 6); - - ~wavelet_decomposition(); - - internal_type ** level_coeffs(int level) const - { - return wavelet_decomp[level]->subbands(); - } - - int level_W(int level) const - { - return wavelet_decomp[level]->width(); - } - - int level_H(int level) const - { - return wavelet_decomp[level]->height(); - } - - int level_stride(int level) const - { - return wavelet_decomp[level]->stride(); - } - - int maxlevel() const - { - return lvltot+1; - } - - int subsample() const - { - return subsamp; - } - template - void reconstruct(E * dst, const float blend = 1.f); - }; - - template - wavelet_decomposition::wavelet_decomposition(E * src, int width, int height, int maxlvl, int subsampling, int skipcrop, int numThreads, int Daub4Len) - : coeff0(NULL), memoryAllocationFailed(false), lvltot(0), subsamp(subsampling), numThreads(numThreads), m_w(width), m_h(height) - { - - //initialize wavelet filters - wavfilt_len = Daub4Len; - wavfilt_offset = Daub4_offset; - wavfilt_anal = new float[2*wavfilt_len]; - wavfilt_synth = new float[2*wavfilt_len]; - - if(wavfilt_len==6) { - for (int n=0; n<2; n++) { - for (int i=0; i(src, buffer[bufferindex^1], lvltot/*level*/, subsamp, m_w, m_h, \ - wavfilt_anal, wavfilt_anal, wavfilt_len, wavfilt_offset, skipcrop, numThreads); - if(wavelet_decomp[lvltot]->memoryAllocationFailed) - memoryAllocationFailed = true; - while(lvltot < maxlvl-1) { - lvltot++; - bufferindex ^= 1; - wavelet_decomp[lvltot] = new wavelet_level(buffer[bufferindex], buffer[bufferindex^1]/*lopass*/, lvltot/*level*/, subsamp, \ - wavelet_decomp[lvltot-1]->width(), wavelet_decomp[lvltot-1]->height(), \ - wavfilt_anal, wavfilt_anal, wavfilt_len, wavfilt_offset, skipcrop, numThreads); - if(wavelet_decomp[lvltot]->memoryAllocationFailed) - memoryAllocationFailed = true; - } - coeff0 = buffer[bufferindex^1]; - delete[] buffer[bufferindex]; - } - - template - void wavelet_decomposition::reconstruct(E * dst, const float blend) { - - if(memoryAllocationFailed) - return; - // data structure is wavcoeffs[scale][channel={lo,hi1,hi2,hi3}][pixel_array] - - if(lvltot >= 1) { - int width = wavelet_decomp[1]->m_w; - int height = wavelet_decomp[1]->m_h; - - E *tmpHi = new (std::nothrow) E[width*height]; - if(tmpHi == NULL) { - memoryAllocationFailed = true; - return; - } - - for (int lvl=lvltot; lvl>0; lvl--) { - E *tmpLo = wavelet_decomp[lvl]->wavcoeffs[2]; // we can use this as buffer - wavelet_decomp[lvl]->reconstruct_level(tmpLo, tmpHi, coeff0, coeff0, wavfilt_synth, wavfilt_synth, wavfilt_len, wavfilt_offset); - delete wavelet_decomp[lvl]; - wavelet_decomp[lvl] = NULL; - } - delete[] tmpHi; - } - - int width = wavelet_decomp[0]->m_w; - int height = wavelet_decomp[0]->m_h2; - E *tmpLo; - if(wavelet_decomp[0]->bigBlockOfMemoryUsed()) // bigBlockOfMemoryUsed means that wavcoeffs[2] points to a block of memory big enough to hold the data - tmpLo = wavelet_decomp[0]->wavcoeffs[2]; - else { // allocate new block of memory - tmpLo = new (std::nothrow) E[width*height]; - if(tmpLo == NULL) { - memoryAllocationFailed = true; - return; - } - } - E *tmpHi = new (std::nothrow) E[width*height]; - if(tmpHi == NULL) { - memoryAllocationFailed = true; - if(!wavelet_decomp[0]->bigBlockOfMemoryUsed()) - delete[] tmpLo; - return; - } - - - wavelet_decomp[0]->reconstruct_level(tmpLo, tmpHi, coeff0, dst, wavfilt_synth, wavfilt_synth, wavfilt_len, wavfilt_offset, blend); - if(!wavelet_decomp[0]->bigBlockOfMemoryUsed()) - delete[] tmpLo; - delete[] tmpHi; - delete wavelet_decomp[0]; - wavelet_decomp[0] = NULL; - delete[] coeff0; - coeff0 = NULL; - } - -}; - -#endif +/* + * This file is part of RawTherapee. + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * 2010 Ilya Popov + * 2012 Emil Martinec + */ + +#ifndef CPLX_WAVELET_DEC_H_INCLUDED +#define CPLX_WAVELET_DEC_H_INCLUDED + +#include +#include + +#include "cplx_wavelet_level.h" +#include "cplx_wavelet_filter_coeffs.h" + +namespace rtengine { + + class wavelet_decomposition + { + public: + + typedef float internal_type; + float *coeff0; + bool memoryAllocationFailed; + + private: + + static const int maxlevels = 10;//should be greater than any conceivable order of decimation + + int lvltot, subsamp; + int numThreads; + int m_w, m_h;//dimensions + + int wavfilt_len, wavfilt_offset; + float *wavfilt_anal; + float *wavfilt_synth; + + + wavelet_level * wavelet_decomp[maxlevels]; + + public: + + template + wavelet_decomposition(E * src, int width, int height, int maxlvl, int subsampling, int skipcrop = 1, int numThreads = 1, int Daub4Len = 6); + + ~wavelet_decomposition(); + + internal_type ** level_coeffs(int level) const + { + return wavelet_decomp[level]->subbands(); + } + + int level_W(int level) const + { + return wavelet_decomp[level]->width(); + } + + int level_H(int level) const + { + return wavelet_decomp[level]->height(); + } + + int level_stride(int level) const + { + return wavelet_decomp[level]->stride(); + } + + int maxlevel() const + { + return lvltot+1; + } + + int subsample() const + { + return subsamp; + } + template + void reconstruct(E * dst, const float blend = 1.f); + }; + + template + wavelet_decomposition::wavelet_decomposition(E * src, int width, int height, int maxlvl, int subsampling, int skipcrop, int numThreads, int Daub4Len) + : coeff0(NULL), memoryAllocationFailed(false), lvltot(0), subsamp(subsampling), numThreads(numThreads), m_w(width), m_h(height) + { + + //initialize wavelet filters + wavfilt_len = Daub4Len; + wavfilt_offset = Daub4_offset; + wavfilt_anal = new float[2*wavfilt_len]; + wavfilt_synth = new float[2*wavfilt_len]; + + if(wavfilt_len==6) { + for (int n=0; n<2; n++) { + for (int i=0; i(src, buffer[bufferindex^1], lvltot/*level*/, subsamp, m_w, m_h, \ + wavfilt_anal, wavfilt_anal, wavfilt_len, wavfilt_offset, skipcrop, numThreads); + if(wavelet_decomp[lvltot]->memoryAllocationFailed) + memoryAllocationFailed = true; + while(lvltot < maxlvl-1) { + lvltot++; + bufferindex ^= 1; + wavelet_decomp[lvltot] = new wavelet_level(buffer[bufferindex], buffer[bufferindex^1]/*lopass*/, lvltot/*level*/, subsamp, \ + wavelet_decomp[lvltot-1]->width(), wavelet_decomp[lvltot-1]->height(), \ + wavfilt_anal, wavfilt_anal, wavfilt_len, wavfilt_offset, skipcrop, numThreads); + if(wavelet_decomp[lvltot]->memoryAllocationFailed) + memoryAllocationFailed = true; + } + coeff0 = buffer[bufferindex^1]; + delete[] buffer[bufferindex]; + } + + template + void wavelet_decomposition::reconstruct(E * dst, const float blend) { + + if(memoryAllocationFailed) + return; + // data structure is wavcoeffs[scale][channel={lo,hi1,hi2,hi3}][pixel_array] + + if(lvltot >= 1) { + int width = wavelet_decomp[1]->m_w; + int height = wavelet_decomp[1]->m_h; + + E *tmpHi = new (std::nothrow) E[width*height]; + if(tmpHi == NULL) { + memoryAllocationFailed = true; + return; + } + + for (int lvl=lvltot; lvl>0; lvl--) { + E *tmpLo = wavelet_decomp[lvl]->wavcoeffs[2]; // we can use this as buffer + wavelet_decomp[lvl]->reconstruct_level(tmpLo, tmpHi, coeff0, coeff0, wavfilt_synth, wavfilt_synth, wavfilt_len, wavfilt_offset); + delete wavelet_decomp[lvl]; + wavelet_decomp[lvl] = NULL; + } + delete[] tmpHi; + } + + int width = wavelet_decomp[0]->m_w; + int height = wavelet_decomp[0]->m_h2; + E *tmpLo; + if(wavelet_decomp[0]->bigBlockOfMemoryUsed()) // bigBlockOfMemoryUsed means that wavcoeffs[2] points to a block of memory big enough to hold the data + tmpLo = wavelet_decomp[0]->wavcoeffs[2]; + else { // allocate new block of memory + tmpLo = new (std::nothrow) E[width*height]; + if(tmpLo == NULL) { + memoryAllocationFailed = true; + return; + } + } + E *tmpHi = new (std::nothrow) E[width*height]; + if(tmpHi == NULL) { + memoryAllocationFailed = true; + if(!wavelet_decomp[0]->bigBlockOfMemoryUsed()) + delete[] tmpLo; + return; + } + + + wavelet_decomp[0]->reconstruct_level(tmpLo, tmpHi, coeff0, dst, wavfilt_synth, wavfilt_synth, wavfilt_len, wavfilt_offset, blend); + if(!wavelet_decomp[0]->bigBlockOfMemoryUsed()) + delete[] tmpLo; + delete[] tmpHi; + delete wavelet_decomp[0]; + wavelet_decomp[0] = NULL; + delete[] coeff0; + coeff0 = NULL; + } + +}; + +#endif diff --git a/rtengine/cplx_wavelet_filter_coeffs.h b/rtengine/cplx_wavelet_filter_coeffs.h index 39fce5a03..3874ba54b 100644 --- a/rtengine/cplx_wavelet_filter_coeffs.h +++ b/rtengine/cplx_wavelet_filter_coeffs.h @@ -1,48 +1,48 @@ -/* - * This file is part of RawTherapee. - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - * - * 2012 Emil Martinec - * 2014 Jacques Desmis - */ - - -namespace rtengine { - -const int Daub4_offset=2; - -const float Daub4_anal0[2][4] ALIGNED16 = {//analysis filter 2 Hall - {0.f, 0.f, 0.5f, 0.5f}, - {-0.5f, 0.5f, 0.f, 0.f}}; - -const float Daub4_anal[2][6] ALIGNED16 = {//Daub4 - {0.f, 0.f, 0.34150635f, 0.59150635f, 0.15849365f, -0.091506351f}, - {-0.091506351f, -0.15849365f, 0.59150635f, -0.34150635f, 0.f, 0.f}}; - -const float Daub4_anal8[2][8] ALIGNED16 = {//Daub6 - {0.f, 0.f, 0.235233605f, 0.57055846f, 0.3251825f, -0.09546721f, -0.060416105f, 0.02490875f}, - {-0.02490875f, -0.060416105f, 0.09546721f, 0.3251825f, -0.57055846f , 0.235233605f, 0.f, 0.f}}; - -const float Daub4_anal12[2][12] ALIGNED16 = {//Daub10 - {0.f, 0.f, 0.11320949f, 0.42697177f, 0.51216347f, 0.09788348f, -0.171328355f, -0.022800565f, 0.054851325f, -0.0044134f, -0.008895935f, 0.002358714f}, - {-0.002358714f, -0.008895935f, 0.0044134f, 0.054851325f, 0.022800565f , -0.171328355f, -0.09788348f, 0.51216347f, -0.42697177f, 0.11320949f, 0.f, 0.f}}; - -const float Daub4_anal16[2][16] ALIGNED16 = {//Daub 14 - {0.f, 0.f, 0.055049715f, 0.28039564f, 0.515574245f, 0.33218624f, -0.10175691f, -0.158417505f, 0.05042335f, 0.057001725f, -0.026891225f, -0.01171997f, 0.008874895f, 0.0003037575f, -0.0012739524f, 0.0002501134f}, - {-0.0002501134f, -0.0012739524f, -0.0003037575f, 0.008874895f, 0.01171997f , -0.026891225f, -0.057001725f, 0.05042335f, 0.158417505f, -0.10175691f, -0.33218624f, 0.515574245f, -0.28039564f, 0.055049715f, 0.f, 0.f}}; - -// if necessary ?? we can add D20 !! -}; - +/* + * This file is part of RawTherapee. + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * 2012 Emil Martinec + * 2014 Jacques Desmis + */ + + +namespace rtengine { + +const int Daub4_offset=2; + +const float Daub4_anal0[2][4] ALIGNED16 = {//analysis filter 2 Hall + {0.f, 0.f, 0.5f, 0.5f}, + {-0.5f, 0.5f, 0.f, 0.f}}; + +const float Daub4_anal[2][6] ALIGNED16 = {//Daub4 + {0.f, 0.f, 0.34150635f, 0.59150635f, 0.15849365f, -0.091506351f}, + {-0.091506351f, -0.15849365f, 0.59150635f, -0.34150635f, 0.f, 0.f}}; + +const float Daub4_anal8[2][8] ALIGNED16 = {//Daub6 + {0.f, 0.f, 0.235233605f, 0.57055846f, 0.3251825f, -0.09546721f, -0.060416105f, 0.02490875f}, + {-0.02490875f, -0.060416105f, 0.09546721f, 0.3251825f, -0.57055846f , 0.235233605f, 0.f, 0.f}}; + +const float Daub4_anal12[2][12] ALIGNED16 = {//Daub10 + {0.f, 0.f, 0.11320949f, 0.42697177f, 0.51216347f, 0.09788348f, -0.171328355f, -0.022800565f, 0.054851325f, -0.0044134f, -0.008895935f, 0.002358714f}, + {-0.002358714f, -0.008895935f, 0.0044134f, 0.054851325f, 0.022800565f , -0.171328355f, -0.09788348f, 0.51216347f, -0.42697177f, 0.11320949f, 0.f, 0.f}}; + +const float Daub4_anal16[2][16] ALIGNED16 = {//Daub 14 + {0.f, 0.f, 0.055049715f, 0.28039564f, 0.515574245f, 0.33218624f, -0.10175691f, -0.158417505f, 0.05042335f, 0.057001725f, -0.026891225f, -0.01171997f, 0.008874895f, 0.0003037575f, -0.0012739524f, 0.0002501134f}, + {-0.0002501134f, -0.0012739524f, -0.0003037575f, 0.008874895f, 0.01171997f , -0.026891225f, -0.057001725f, 0.05042335f, 0.158417505f, -0.10175691f, -0.33218624f, 0.515574245f, -0.28039564f, 0.055049715f, 0.f, 0.f}}; + +// if necessary ?? we can add D20 !! +}; + diff --git a/rtengine/cplx_wavelet_level.h b/rtengine/cplx_wavelet_level.h index 1c1efde27..862ba3552 100644 --- a/rtengine/cplx_wavelet_level.h +++ b/rtengine/cplx_wavelet_level.h @@ -1,654 +1,654 @@ -/* - * This file is part of RawTherapee. - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - * - * 2010 Ilya Popov - * 2012 Emil Martinec - * 2014 Ingo Weyrich - */ - -#ifndef CPLX_WAVELET_LEVEL_H_INCLUDED -#define CPLX_WAVELET_LEVEL_H_INCLUDED - -#include -#include "rt_math.h" -#include "opthelper.h" -#include "stdio.h" -namespace rtengine { - - template - class wavelet_level - { - - // level of decomposition - int lvl; - - // whether to subsample the output - bool subsamp_out; - - int numThreads; - - // spacing of filter taps - int skip; - - bool bigBlockOfMemory; - // allocation and destruction of data storage - T ** create(int n); - void destroy(T ** subbands); - - // load a row/column of input data, possibly with padding - - void AnalysisFilterHaarVertical (const T * const srcbuffer, T * dstLo, T * dstHi, const int width, const int height, const int row); - void AnalysisFilterHaarHorizontal (const T * const srcbuffer, T * dstLo, T * dstHi, const int width, const int row); - void SynthesisFilterHaarHorizontal (const T * const srcLo, const T * const srcHi, T * dst, const int width, const int height); - void SynthesisFilterHaarVertical (const T * const srcLo, const T * const srcHi, T * dst, const int width, const int height); - - void AnalysisFilterSubsampHorizontal (T * srcbuffer, T * dstLo, T * dstHi, float *filterLo, float *filterHi, - const int taps, const int offset, const int srcwidth, const int dstwidth, const int row); -#ifdef __SSE2__ - void AnalysisFilterSubsampVertical (T * srcbuffer, T * dstLo, T * dstHi, float (*filterLo)[4], float (*filterHi)[4], - const int taps, const int offset, const int width, const int height, const int row); -#else - void AnalysisFilterSubsampVertical (T * srcbuffer, T * dstLo, T * dstHi, float *filterLo, float *filterHi, - int const taps, const int offset, const int width, const int height, const int row); -#endif - void SynthesisFilterSubsampHorizontal (T * srcLo, T * srcHi, T * dst, - float *filterLo, float *filterHi, const int taps, const int offset, const int scrwidth, const int dstwidth, const int height); -#ifdef __SSE2__ - void SynthesisFilterSubsampVertical (T * srcLo, T * srcHi, T * dst, float (*filterLo)[4], float (*filterHi)[4], const int taps, const int offset, const int width, const int srcheight, const int dstheight, const float blend); -#else - void SynthesisFilterSubsampVertical (T * srcLo, T * srcHi, T * dst, float *filterLo, float *filterHi, const int taps, const int offset, const int width, const int srcheight, const int dstheight, const float blend); -#endif - public: - bool memoryAllocationFailed; - - T ** wavcoeffs; - // full size - int m_w, m_h; - - // size of low frequency part - int m_w2, m_h2; - - template - wavelet_level(E * src, E * dst, int level, int subsamp, int w, int h, float *filterV, float *filterH, int len, int offset, int skipcrop, int numThreads) - : lvl(level), subsamp_out((subsamp>>level)&1), numThreads(numThreads), skip(1<>n)&1); - } - skip /= skipcrop; - if(skip < 1) skip=1; - - } - m_w2 = (subsamp_out ? (w+1)/2 : w); - m_h2 = (subsamp_out ? (h+1)/2 : h); - - wavcoeffs = create((m_w2)*(m_h2)); - if(!memoryAllocationFailed) - decompose_level(src, dst, filterV, filterH, len, offset); - - } - - ~wavelet_level() { - destroy(wavcoeffs); - } - - T ** subbands() const { - return wavcoeffs; - } - - T * lopass() const { - return wavcoeffs[0]; - } - - int width() const { - return m_w2; - } - - int height() const { - return m_h2; - } - - int stride() const { - return skip; - } - - bool bigBlockOfMemoryUsed() const { - return bigBlockOfMemory; - } - - template - void decompose_level(E *src, E *dst, float *filterV, float *filterH, int len, int offset); - - template - void reconstruct_level(E* tmpLo, E* tmpHi, E *src, E *dst, float *filterV, float *filterH, int taps, int offset, const float blend = 1.f); - }; - - template - T ** wavelet_level::create(int n) { - T * data = new (std::nothrow) T[3*n]; - if(data == NULL) { - bigBlockOfMemory = false; - } - T ** subbands = new T*[4]; - for(int j = 1; j < 4; j++) { - if(bigBlockOfMemory) - subbands[j] = data + n * (j-1); - else { - subbands[j] = new (std::nothrow) T[n]; - if(subbands[j] == NULL) { - printf("Couldn't allocate memory in level %d of wavelet\n",lvl); - memoryAllocationFailed = true; - } - } - } - return subbands; - } - - template - void wavelet_level::destroy(T ** subbands) { - if(subbands) { - if(bigBlockOfMemory) - delete[] subbands[1]; - else { - for(int j = 1; j < 4; j++) { - if(subbands[j] != NULL) - delete[] subbands[j]; - } - } - delete[] subbands; - } - } - - template - void wavelet_level::AnalysisFilterHaarHorizontal (const T * const RESTRICT srcbuffer, T * RESTRICT dstLo, T * RESTRICT dstHi, const int width, const int row) { - /* Basic convolution code - * Applies a Haar filter - */ - for(int i = 0; i < (width - skip); i++) { - dstLo[row*width+i] = (srcbuffer[i] + srcbuffer[i+skip]); - dstHi[row*width+i] = (srcbuffer[i] - srcbuffer[i+skip]); - } - for(int i = max(width-skip,skip); i < (width); i++) { - dstLo[row*width+i] = (srcbuffer[i] + srcbuffer[i-skip]); - dstHi[row*width+i] = (srcbuffer[i] - srcbuffer[i-skip]); - } - } - - template void wavelet_level::AnalysisFilterHaarVertical (const T * const RESTRICT srcbuffer, T * RESTRICT dstLo, T * RESTRICT dstHi, const int width, const int height, const int row) { - /* Basic convolution code - * Applies a Haar filter - */ - if(row < (height - skip)) { - for(int j=0;j=max(height-skip,skip)) { - for(int j=0;j void wavelet_level::SynthesisFilterHaarHorizontal (const T * const RESTRICT srcLo, const T * const RESTRICT srcHi, T * RESTRICT dst, const int width, const int height) { - - /* Basic convolution code - * Applies a Haar filter - * - */ -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(numThreads) if(numThreads>1) -#endif - for (int k=0; k void wavelet_level::SynthesisFilterHaarVertical (const T * const RESTRICT srcLo, const T * const RESTRICT srcHi, T * RESTRICT dst, const int width, const int height) { - - /* Basic convolution code - * Applies a Haar filter - * - */ -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel num_threads(numThreads) if(numThreads>1) -#endif -{ -#ifdef _RT_NESTED_OPENMP -#pragma omp for nowait -#endif - for(int i = 0; i < skip; i++) { - for(int j=0;j - void wavelet_level::AnalysisFilterSubsampHorizontal (T * RESTRICT srcbuffer, T * RESTRICT dstLo, T * RESTRICT dstHi, float * RESTRICT filterLo, float *RESTRICT filterHi, - const int taps, const int offset, const int srcwidth, const int dstwidth, const int row) { - /* Basic convolution code - * Applies an FIR filter 'filter' with filter length 'taps', - * aligning the 'offset' element of the filter with - * the input pixel, and skipping 'skip' pixels between taps - * Output is subsampled by two - */ - // calculate coefficients - for(int i = 0; i < srcwidth; i+=2) { - float lo = 0.f, hi = 0.f; - if (LIKELY(i>skip*taps && i SSEFUNCTION void wavelet_level::AnalysisFilterSubsampVertical (T * RESTRICT srcbuffer, T * RESTRICT dstLo, T * RESTRICT dstHi, float (* RESTRICT filterLo)[4], float (* RESTRICT filterHi)[4], - const int taps, const int offset, const int width, const int height, const int row) { - - /* Basic convolution code - * Applies an FIR filter 'filter' with filter length 'taps', - * aligning the 'offset' element of the filter with - * the input pixel, and skipping 'skip' pixels between taps - * Output is subsampled by two - */ - - // calculate coefficients - if (LIKELY(row>skip*taps && row void wavelet_level::AnalysisFilterSubsampVertical (T * RESTRICT srcbuffer, T * RESTRICT dstLo, T * RESTRICT dstHi, float * RESTRICT filterLo, float * RESTRICT filterHi, - const int taps, const int offset, const int width, const int height, const int row) { - - /* Basic convolution code - * Applies an FIR filter 'filter' with filter length 'taps', - * aligning the 'offset' element of the filter with - * the input pixel, and skipping 'skip' pixels between taps - * Output is subsampled by two - */ - - // calculate coefficients - if (LIKELY(row>skip*taps && row void wavelet_level::SynthesisFilterSubsampHorizontal (T * RESTRICT srcLo, T * RESTRICT srcHi, T * RESTRICT dst, float * RESTRICT filterLo, float * RESTRICT filterHi, const int taps, const int offset, const int srcwidth, const int dstwidth, const int height) { - - /* Basic convolution code - * Applies an FIR filter 'filter' with filter length 'taps', - * aligning the 'offset' element of the filter with - * the input pixel, and skipping 'skip' pixels between taps - * Output is subsampled by two - */ - - // calculate coefficients - int shift = skip*(taps-offset-1);//align filter with data -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(numThreads) if(numThreads>1) -#endif - for (int k=0; k SSEFUNCTION void wavelet_level::SynthesisFilterSubsampVertical (T * RESTRICT srcLo, T * RESTRICT srcHi, T * RESTRICT dst, float (* RESTRICT filterLo)[4], float (* RESTRICT filterHi)[4], const int taps, const int offset, const int width, const int srcheight, const int dstheight, const float blend) - { - - /* Basic convolution code - * Applies an FIR filter 'filter' with filter length 'taps', - * aligning the 'offset' element of the filter with - * the input pixel, and skipping 'skip' pixels between taps - * Output is subsampled by two - */ - const float srcFactor = 1.f - blend; - // calculate coefficients - int shift=skip*(taps-offset-1);//align filter with data - __m128 fourv = _mm_set1_ps(4.f); - __m128 srcFactorv = _mm_set1_ps(srcFactor); - __m128 dstFactorv = _mm_set1_ps(blend); -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(numThreads) if(numThreads>1) -#endif - for(int i = 0; i < dstheight; i++) { - int i_src = (i+shift)/2; - int begin = (i+shift)%2; - //TODO: this is correct only if skip=1; otherwise, want to work with cosets of length 'skip' - if (LIKELY(i>skip*taps && i<(dstheight-skip*taps))) {//bulk - int k; - for (k=0; k void wavelet_level::SynthesisFilterSubsampVertical (T * RESTRICT srcLo, T * RESTRICT srcHi, T * RESTRICT dst, float * RESTRICT filterLo, float * RESTRICT filterHi, const int taps, const int offset, const int width, const int srcheight, const int dstheight, const float blend) - { - - /* Basic convolution code - * Applies an FIR filter 'filter' with filter length 'taps', - * aligning the 'offset' element of the filter with - * the input pixel, and skipping 'skip' pixels between taps - * Output is subsampled by two - */ - - const float srcFactor = 1.f - blend; - // calculate coefficients - int shift=skip*(taps-offset-1);//align filter with data - -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(numThreads) if(numThreads>1) -#endif - for(int i = 0; i < dstheight; i++) { - int i_src = (i+shift)/2; - int begin = (i+shift)%2; - //TODO: this is correct only if skip=1; otherwise, want to work with cosets of length 'skip' - if (LIKELY(i>skip*taps && i<(dstheight-skip*taps))) {//bulk - for (int k=0; k template SSEFUNCTION void wavelet_level::decompose_level(E *src, E *dst, float *filterV, float *filterH, int taps, int offset) { - - /* filter along rows and columns */ - float filterVarray[2*taps][4] ALIGNED64; - if(subsamp_out) { - for(int i=0;i<2*taps;i++) { - for(int j=0;j<4;j++) { - filterVarray[i][j] = filterV[i]; - } - } - } -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel num_threads(numThreads) if(numThreads>1) -#endif -{ - T tmpLo[m_w] ALIGNED64; - T tmpHi[m_w] ALIGNED64; - if(subsamp_out) { -#ifdef _RT_NESTED_OPENMP -#pragma omp for -#endif - for(int row=0;row template void wavelet_level::decompose_level(E *src, E *dst, float *filterV, float *filterH, int taps, int offset) { - -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel num_threads(numThreads) if(numThreads>1) -#endif -{ - T tmpLo[m_w] ALIGNED64; - T tmpHi[m_w] ALIGNED64; - /* filter along rows and columns */ - if(subsamp_out) { -#ifdef _RT_NESTED_OPENMP -#pragma omp for -#endif - for(int row=0;row template SSEFUNCTION void wavelet_level::reconstruct_level(E* tmpLo, E* tmpHi, E * src, E *dst, float *filterV, float *filterH, int taps, int offset, const float blend) { - if(memoryAllocationFailed) - return; - - /* filter along rows and columns */ - if (subsamp_out) { - float filterVarray[2*taps][4] ALIGNED64; - for(int i=0;i<2*taps;i++) { - for(int j=0;j<4;j++) { - filterVarray[i][j] = filterV[i]; - } - } - SynthesisFilterSubsampHorizontal (wavcoeffs[2], wavcoeffs[3], tmpHi, filterH, filterH+taps, taps, offset, m_w2, m_w, m_h2); - SynthesisFilterSubsampHorizontal (src, wavcoeffs[1], tmpLo, filterH, filterH+taps, taps, offset, m_w2, m_w, m_h2); - SynthesisFilterSubsampVertical (tmpLo, tmpHi, dst, filterVarray, filterVarray+taps, taps, offset, m_w, m_h2, m_h, blend); - } else { - SynthesisFilterHaarHorizontal (wavcoeffs[2], wavcoeffs[3], tmpHi, m_w, m_h2); - SynthesisFilterHaarHorizontal (src, wavcoeffs[1], tmpLo, m_w, m_h2); - SynthesisFilterHaarVertical (tmpLo, tmpHi, dst, m_w, m_h); - } - } -#else - template template void wavelet_level::reconstruct_level(E* tmpLo, E* tmpHi, E * src, E *dst, float *filterV, float *filterH, int taps, int offset, const float blend) { - if(memoryAllocationFailed) - return; - /* filter along rows and columns */ - if (subsamp_out) { - SynthesisFilterSubsampHorizontal (wavcoeffs[2], wavcoeffs[3], tmpHi, filterH, filterH+taps, taps, offset, m_w2, m_w, m_h2); - SynthesisFilterSubsampHorizontal (src, wavcoeffs[1], tmpLo, filterH, filterH+taps, taps, offset, m_w2, m_w, m_h2); - SynthesisFilterSubsampVertical (tmpLo, tmpHi, dst, filterV, filterV+taps, taps, offset, m_w, m_h2, m_h, blend); - } else { - SynthesisFilterHaarHorizontal (wavcoeffs[2], wavcoeffs[3], tmpHi, m_w, m_h2); - SynthesisFilterHaarHorizontal (src, wavcoeffs[1], tmpLo, m_w, m_h2); - SynthesisFilterHaarVertical (tmpLo, tmpHi, dst, m_w, m_h); - } - } -#endif -}; - -#endif +/* + * This file is part of RawTherapee. + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * 2010 Ilya Popov + * 2012 Emil Martinec + * 2014 Ingo Weyrich + */ + +#ifndef CPLX_WAVELET_LEVEL_H_INCLUDED +#define CPLX_WAVELET_LEVEL_H_INCLUDED + +#include +#include "rt_math.h" +#include "opthelper.h" +#include "stdio.h" +namespace rtengine { + + template + class wavelet_level + { + + // level of decomposition + int lvl; + + // whether to subsample the output + bool subsamp_out; + + int numThreads; + + // spacing of filter taps + int skip; + + bool bigBlockOfMemory; + // allocation and destruction of data storage + T ** create(int n); + void destroy(T ** subbands); + + // load a row/column of input data, possibly with padding + + void AnalysisFilterHaarVertical (const T * const srcbuffer, T * dstLo, T * dstHi, const int width, const int height, const int row); + void AnalysisFilterHaarHorizontal (const T * const srcbuffer, T * dstLo, T * dstHi, const int width, const int row); + void SynthesisFilterHaarHorizontal (const T * const srcLo, const T * const srcHi, T * dst, const int width, const int height); + void SynthesisFilterHaarVertical (const T * const srcLo, const T * const srcHi, T * dst, const int width, const int height); + + void AnalysisFilterSubsampHorizontal (T * srcbuffer, T * dstLo, T * dstHi, float *filterLo, float *filterHi, + const int taps, const int offset, const int srcwidth, const int dstwidth, const int row); +#ifdef __SSE2__ + void AnalysisFilterSubsampVertical (T * srcbuffer, T * dstLo, T * dstHi, float (*filterLo)[4], float (*filterHi)[4], + const int taps, const int offset, const int width, const int height, const int row); +#else + void AnalysisFilterSubsampVertical (T * srcbuffer, T * dstLo, T * dstHi, float *filterLo, float *filterHi, + int const taps, const int offset, const int width, const int height, const int row); +#endif + void SynthesisFilterSubsampHorizontal (T * srcLo, T * srcHi, T * dst, + float *filterLo, float *filterHi, const int taps, const int offset, const int scrwidth, const int dstwidth, const int height); +#ifdef __SSE2__ + void SynthesisFilterSubsampVertical (T * srcLo, T * srcHi, T * dst, float (*filterLo)[4], float (*filterHi)[4], const int taps, const int offset, const int width, const int srcheight, const int dstheight, const float blend); +#else + void SynthesisFilterSubsampVertical (T * srcLo, T * srcHi, T * dst, float *filterLo, float *filterHi, const int taps, const int offset, const int width, const int srcheight, const int dstheight, const float blend); +#endif + public: + bool memoryAllocationFailed; + + T ** wavcoeffs; + // full size + int m_w, m_h; + + // size of low frequency part + int m_w2, m_h2; + + template + wavelet_level(E * src, E * dst, int level, int subsamp, int w, int h, float *filterV, float *filterH, int len, int offset, int skipcrop, int numThreads) + : lvl(level), subsamp_out((subsamp>>level)&1), numThreads(numThreads), skip(1<>n)&1); + } + skip /= skipcrop; + if(skip < 1) skip=1; + + } + m_w2 = (subsamp_out ? (w+1)/2 : w); + m_h2 = (subsamp_out ? (h+1)/2 : h); + + wavcoeffs = create((m_w2)*(m_h2)); + if(!memoryAllocationFailed) + decompose_level(src, dst, filterV, filterH, len, offset); + + } + + ~wavelet_level() { + destroy(wavcoeffs); + } + + T ** subbands() const { + return wavcoeffs; + } + + T * lopass() const { + return wavcoeffs[0]; + } + + int width() const { + return m_w2; + } + + int height() const { + return m_h2; + } + + int stride() const { + return skip; + } + + bool bigBlockOfMemoryUsed() const { + return bigBlockOfMemory; + } + + template + void decompose_level(E *src, E *dst, float *filterV, float *filterH, int len, int offset); + + template + void reconstruct_level(E* tmpLo, E* tmpHi, E *src, E *dst, float *filterV, float *filterH, int taps, int offset, const float blend = 1.f); + }; + + template + T ** wavelet_level::create(int n) { + T * data = new (std::nothrow) T[3*n]; + if(data == NULL) { + bigBlockOfMemory = false; + } + T ** subbands = new T*[4]; + for(int j = 1; j < 4; j++) { + if(bigBlockOfMemory) + subbands[j] = data + n * (j-1); + else { + subbands[j] = new (std::nothrow) T[n]; + if(subbands[j] == NULL) { + printf("Couldn't allocate memory in level %d of wavelet\n",lvl); + memoryAllocationFailed = true; + } + } + } + return subbands; + } + + template + void wavelet_level::destroy(T ** subbands) { + if(subbands) { + if(bigBlockOfMemory) + delete[] subbands[1]; + else { + for(int j = 1; j < 4; j++) { + if(subbands[j] != NULL) + delete[] subbands[j]; + } + } + delete[] subbands; + } + } + + template + void wavelet_level::AnalysisFilterHaarHorizontal (const T * const RESTRICT srcbuffer, T * RESTRICT dstLo, T * RESTRICT dstHi, const int width, const int row) { + /* Basic convolution code + * Applies a Haar filter + */ + for(int i = 0; i < (width - skip); i++) { + dstLo[row*width+i] = (srcbuffer[i] + srcbuffer[i+skip]); + dstHi[row*width+i] = (srcbuffer[i] - srcbuffer[i+skip]); + } + for(int i = max(width-skip,skip); i < (width); i++) { + dstLo[row*width+i] = (srcbuffer[i] + srcbuffer[i-skip]); + dstHi[row*width+i] = (srcbuffer[i] - srcbuffer[i-skip]); + } + } + + template void wavelet_level::AnalysisFilterHaarVertical (const T * const RESTRICT srcbuffer, T * RESTRICT dstLo, T * RESTRICT dstHi, const int width, const int height, const int row) { + /* Basic convolution code + * Applies a Haar filter + */ + if(row < (height - skip)) { + for(int j=0;j=max(height-skip,skip)) { + for(int j=0;j void wavelet_level::SynthesisFilterHaarHorizontal (const T * const RESTRICT srcLo, const T * const RESTRICT srcHi, T * RESTRICT dst, const int width, const int height) { + + /* Basic convolution code + * Applies a Haar filter + * + */ +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(numThreads) if(numThreads>1) +#endif + for (int k=0; k void wavelet_level::SynthesisFilterHaarVertical (const T * const RESTRICT srcLo, const T * const RESTRICT srcHi, T * RESTRICT dst, const int width, const int height) { + + /* Basic convolution code + * Applies a Haar filter + * + */ +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel num_threads(numThreads) if(numThreads>1) +#endif +{ +#ifdef _RT_NESTED_OPENMP +#pragma omp for nowait +#endif + for(int i = 0; i < skip; i++) { + for(int j=0;j + void wavelet_level::AnalysisFilterSubsampHorizontal (T * RESTRICT srcbuffer, T * RESTRICT dstLo, T * RESTRICT dstHi, float * RESTRICT filterLo, float *RESTRICT filterHi, + const int taps, const int offset, const int srcwidth, const int dstwidth, const int row) { + /* Basic convolution code + * Applies an FIR filter 'filter' with filter length 'taps', + * aligning the 'offset' element of the filter with + * the input pixel, and skipping 'skip' pixels between taps + * Output is subsampled by two + */ + // calculate coefficients + for(int i = 0; i < srcwidth; i+=2) { + float lo = 0.f, hi = 0.f; + if (LIKELY(i>skip*taps && i SSEFUNCTION void wavelet_level::AnalysisFilterSubsampVertical (T * RESTRICT srcbuffer, T * RESTRICT dstLo, T * RESTRICT dstHi, float (* RESTRICT filterLo)[4], float (* RESTRICT filterHi)[4], + const int taps, const int offset, const int width, const int height, const int row) { + + /* Basic convolution code + * Applies an FIR filter 'filter' with filter length 'taps', + * aligning the 'offset' element of the filter with + * the input pixel, and skipping 'skip' pixels between taps + * Output is subsampled by two + */ + + // calculate coefficients + if (LIKELY(row>skip*taps && row void wavelet_level::AnalysisFilterSubsampVertical (T * RESTRICT srcbuffer, T * RESTRICT dstLo, T * RESTRICT dstHi, float * RESTRICT filterLo, float * RESTRICT filterHi, + const int taps, const int offset, const int width, const int height, const int row) { + + /* Basic convolution code + * Applies an FIR filter 'filter' with filter length 'taps', + * aligning the 'offset' element of the filter with + * the input pixel, and skipping 'skip' pixels between taps + * Output is subsampled by two + */ + + // calculate coefficients + if (LIKELY(row>skip*taps && row void wavelet_level::SynthesisFilterSubsampHorizontal (T * RESTRICT srcLo, T * RESTRICT srcHi, T * RESTRICT dst, float * RESTRICT filterLo, float * RESTRICT filterHi, const int taps, const int offset, const int srcwidth, const int dstwidth, const int height) { + + /* Basic convolution code + * Applies an FIR filter 'filter' with filter length 'taps', + * aligning the 'offset' element of the filter with + * the input pixel, and skipping 'skip' pixels between taps + * Output is subsampled by two + */ + + // calculate coefficients + int shift = skip*(taps-offset-1);//align filter with data +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(numThreads) if(numThreads>1) +#endif + for (int k=0; k SSEFUNCTION void wavelet_level::SynthesisFilterSubsampVertical (T * RESTRICT srcLo, T * RESTRICT srcHi, T * RESTRICT dst, float (* RESTRICT filterLo)[4], float (* RESTRICT filterHi)[4], const int taps, const int offset, const int width, const int srcheight, const int dstheight, const float blend) + { + + /* Basic convolution code + * Applies an FIR filter 'filter' with filter length 'taps', + * aligning the 'offset' element of the filter with + * the input pixel, and skipping 'skip' pixels between taps + * Output is subsampled by two + */ + const float srcFactor = 1.f - blend; + // calculate coefficients + int shift=skip*(taps-offset-1);//align filter with data + __m128 fourv = _mm_set1_ps(4.f); + __m128 srcFactorv = _mm_set1_ps(srcFactor); + __m128 dstFactorv = _mm_set1_ps(blend); +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(numThreads) if(numThreads>1) +#endif + for(int i = 0; i < dstheight; i++) { + int i_src = (i+shift)/2; + int begin = (i+shift)%2; + //TODO: this is correct only if skip=1; otherwise, want to work with cosets of length 'skip' + if (LIKELY(i>skip*taps && i<(dstheight-skip*taps))) {//bulk + int k; + for (k=0; k void wavelet_level::SynthesisFilterSubsampVertical (T * RESTRICT srcLo, T * RESTRICT srcHi, T * RESTRICT dst, float * RESTRICT filterLo, float * RESTRICT filterHi, const int taps, const int offset, const int width, const int srcheight, const int dstheight, const float blend) + { + + /* Basic convolution code + * Applies an FIR filter 'filter' with filter length 'taps', + * aligning the 'offset' element of the filter with + * the input pixel, and skipping 'skip' pixels between taps + * Output is subsampled by two + */ + + const float srcFactor = 1.f - blend; + // calculate coefficients + int shift=skip*(taps-offset-1);//align filter with data + +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(numThreads) if(numThreads>1) +#endif + for(int i = 0; i < dstheight; i++) { + int i_src = (i+shift)/2; + int begin = (i+shift)%2; + //TODO: this is correct only if skip=1; otherwise, want to work with cosets of length 'skip' + if (LIKELY(i>skip*taps && i<(dstheight-skip*taps))) {//bulk + for (int k=0; k template SSEFUNCTION void wavelet_level::decompose_level(E *src, E *dst, float *filterV, float *filterH, int taps, int offset) { + + /* filter along rows and columns */ + float filterVarray[2*taps][4] ALIGNED64; + if(subsamp_out) { + for(int i=0;i<2*taps;i++) { + for(int j=0;j<4;j++) { + filterVarray[i][j] = filterV[i]; + } + } + } +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel num_threads(numThreads) if(numThreads>1) +#endif +{ + T tmpLo[m_w] ALIGNED64; + T tmpHi[m_w] ALIGNED64; + if(subsamp_out) { +#ifdef _RT_NESTED_OPENMP +#pragma omp for +#endif + for(int row=0;row template void wavelet_level::decompose_level(E *src, E *dst, float *filterV, float *filterH, int taps, int offset) { + +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel num_threads(numThreads) if(numThreads>1) +#endif +{ + T tmpLo[m_w] ALIGNED64; + T tmpHi[m_w] ALIGNED64; + /* filter along rows and columns */ + if(subsamp_out) { +#ifdef _RT_NESTED_OPENMP +#pragma omp for +#endif + for(int row=0;row template SSEFUNCTION void wavelet_level::reconstruct_level(E* tmpLo, E* tmpHi, E * src, E *dst, float *filterV, float *filterH, int taps, int offset, const float blend) { + if(memoryAllocationFailed) + return; + + /* filter along rows and columns */ + if (subsamp_out) { + float filterVarray[2*taps][4] ALIGNED64; + for(int i=0;i<2*taps;i++) { + for(int j=0;j<4;j++) { + filterVarray[i][j] = filterV[i]; + } + } + SynthesisFilterSubsampHorizontal (wavcoeffs[2], wavcoeffs[3], tmpHi, filterH, filterH+taps, taps, offset, m_w2, m_w, m_h2); + SynthesisFilterSubsampHorizontal (src, wavcoeffs[1], tmpLo, filterH, filterH+taps, taps, offset, m_w2, m_w, m_h2); + SynthesisFilterSubsampVertical (tmpLo, tmpHi, dst, filterVarray, filterVarray+taps, taps, offset, m_w, m_h2, m_h, blend); + } else { + SynthesisFilterHaarHorizontal (wavcoeffs[2], wavcoeffs[3], tmpHi, m_w, m_h2); + SynthesisFilterHaarHorizontal (src, wavcoeffs[1], tmpLo, m_w, m_h2); + SynthesisFilterHaarVertical (tmpLo, tmpHi, dst, m_w, m_h); + } + } +#else + template template void wavelet_level::reconstruct_level(E* tmpLo, E* tmpHi, E * src, E *dst, float *filterV, float *filterH, int taps, int offset, const float blend) { + if(memoryAllocationFailed) + return; + /* filter along rows and columns */ + if (subsamp_out) { + SynthesisFilterSubsampHorizontal (wavcoeffs[2], wavcoeffs[3], tmpHi, filterH, filterH+taps, taps, offset, m_w2, m_w, m_h2); + SynthesisFilterSubsampHorizontal (src, wavcoeffs[1], tmpLo, filterH, filterH+taps, taps, offset, m_w2, m_w, m_h2); + SynthesisFilterSubsampVertical (tmpLo, tmpHi, dst, filterV, filterV+taps, taps, offset, m_w, m_h2, m_h, blend); + } else { + SynthesisFilterHaarHorizontal (wavcoeffs[2], wavcoeffs[3], tmpHi, m_w, m_h2); + SynthesisFilterHaarHorizontal (src, wavcoeffs[1], tmpLo, m_w, m_h2); + SynthesisFilterHaarVertical (tmpLo, tmpHi, dst, m_w, m_h); + } + } +#endif +}; + +#endif diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 93ed24257..907d7d7c8 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -1,1596 +1,1596 @@ -/* -* This file is part of RawTherapee. -* -* Copyright (c) 2012 Oliver Duis -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -*/ -#include - -#include "dcp.h" -#include "safegtk.h" -#include "iccmatrices.h" -#include "iccstore.h" -#include "rawimagesource.h" -#include "improcfun.h" -#include "rt_math.h" - -using namespace std; -using namespace rtengine; -using namespace rtexif; - -static const float adobe_camera_raw_default_curve[] = { - 0.00000f, 0.00078f, 0.00160f, 0.00242f, - 0.00314f, 0.00385f, 0.00460f, 0.00539f, - 0.00623f, 0.00712f, 0.00806f, 0.00906f, - 0.01012f, 0.01122f, 0.01238f, 0.01359f, - 0.01485f, 0.01616f, 0.01751f, 0.01890f, - 0.02033f, 0.02180f, 0.02331f, 0.02485f, - 0.02643f, 0.02804f, 0.02967f, 0.03134f, - 0.03303f, 0.03475f, 0.03648f, 0.03824f, - 0.04002f, 0.04181f, 0.04362f, 0.04545f, - 0.04730f, 0.04916f, 0.05103f, 0.05292f, - 0.05483f, 0.05675f, 0.05868f, 0.06063f, - 0.06259f, 0.06457f, 0.06655f, 0.06856f, - 0.07057f, 0.07259f, 0.07463f, 0.07668f, - 0.07874f, 0.08081f, 0.08290f, 0.08499f, - 0.08710f, 0.08921f, 0.09134f, 0.09348f, - 0.09563f, 0.09779f, 0.09996f, 0.10214f, - 0.10433f, 0.10652f, 0.10873f, 0.11095f, - 0.11318f, 0.11541f, 0.11766f, 0.11991f, - 0.12218f, 0.12445f, 0.12673f, 0.12902f, - 0.13132f, 0.13363f, 0.13595f, 0.13827f, - 0.14061f, 0.14295f, 0.14530f, 0.14765f, - 0.15002f, 0.15239f, 0.15477f, 0.15716f, - 0.15956f, 0.16197f, 0.16438f, 0.16680f, - 0.16923f, 0.17166f, 0.17410f, 0.17655f, - 0.17901f, 0.18148f, 0.18395f, 0.18643f, - 0.18891f, 0.19141f, 0.19391f, 0.19641f, - 0.19893f, 0.20145f, 0.20398f, 0.20651f, - 0.20905f, 0.21160f, 0.21416f, 0.21672f, - 0.21929f, 0.22185f, 0.22440f, 0.22696f, - 0.22950f, 0.23204f, 0.23458f, 0.23711f, - 0.23963f, 0.24215f, 0.24466f, 0.24717f, - 0.24967f, 0.25216f, 0.25465f, 0.25713f, - 0.25961f, 0.26208f, 0.26454f, 0.26700f, - 0.26945f, 0.27189f, 0.27433f, 0.27676f, - 0.27918f, 0.28160f, 0.28401f, 0.28641f, - 0.28881f, 0.29120f, 0.29358f, 0.29596f, - 0.29833f, 0.30069f, 0.30305f, 0.30540f, - 0.30774f, 0.31008f, 0.31241f, 0.31473f, - 0.31704f, 0.31935f, 0.32165f, 0.32395f, - 0.32623f, 0.32851f, 0.33079f, 0.33305f, - 0.33531f, 0.33756f, 0.33981f, 0.34205f, - 0.34428f, 0.34650f, 0.34872f, 0.35093f, - 0.35313f, 0.35532f, 0.35751f, 0.35969f, - 0.36187f, 0.36404f, 0.36620f, 0.36835f, - 0.37050f, 0.37264f, 0.37477f, 0.37689f, - 0.37901f, 0.38112f, 0.38323f, 0.38533f, - 0.38742f, 0.38950f, 0.39158f, 0.39365f, - 0.39571f, 0.39777f, 0.39982f, 0.40186f, - 0.40389f, 0.40592f, 0.40794f, 0.40996f, - 0.41197f, 0.41397f, 0.41596f, 0.41795f, - 0.41993f, 0.42191f, 0.42388f, 0.42584f, - 0.42779f, 0.42974f, 0.43168f, 0.43362f, - 0.43554f, 0.43747f, 0.43938f, 0.44129f, - 0.44319f, 0.44509f, 0.44698f, 0.44886f, - 0.45073f, 0.45260f, 0.45447f, 0.45632f, - 0.45817f, 0.46002f, 0.46186f, 0.46369f, - 0.46551f, 0.46733f, 0.46914f, 0.47095f, - 0.47275f, 0.47454f, 0.47633f, 0.47811f, - 0.47989f, 0.48166f, 0.48342f, 0.48518f, - 0.48693f, 0.48867f, 0.49041f, 0.49214f, - 0.49387f, 0.49559f, 0.49730f, 0.49901f, - 0.50072f, 0.50241f, 0.50410f, 0.50579f, - 0.50747f, 0.50914f, 0.51081f, 0.51247f, - 0.51413f, 0.51578f, 0.51742f, 0.51906f, - 0.52069f, 0.52232f, 0.52394f, 0.52556f, - 0.52717f, 0.52878f, 0.53038f, 0.53197f, - 0.53356f, 0.53514f, 0.53672f, 0.53829f, - 0.53986f, 0.54142f, 0.54297f, 0.54452f, - 0.54607f, 0.54761f, 0.54914f, 0.55067f, - 0.55220f, 0.55371f, 0.55523f, 0.55673f, - 0.55824f, 0.55973f, 0.56123f, 0.56271f, - 0.56420f, 0.56567f, 0.56715f, 0.56861f, - 0.57007f, 0.57153f, 0.57298f, 0.57443f, - 0.57587f, 0.57731f, 0.57874f, 0.58017f, - 0.58159f, 0.58301f, 0.58443f, 0.58583f, - 0.58724f, 0.58864f, 0.59003f, 0.59142f, - 0.59281f, 0.59419f, 0.59556f, 0.59694f, - 0.59830f, 0.59966f, 0.60102f, 0.60238f, - 0.60373f, 0.60507f, 0.60641f, 0.60775f, - 0.60908f, 0.61040f, 0.61173f, 0.61305f, - 0.61436f, 0.61567f, 0.61698f, 0.61828f, - 0.61957f, 0.62087f, 0.62216f, 0.62344f, - 0.62472f, 0.62600f, 0.62727f, 0.62854f, - 0.62980f, 0.63106f, 0.63232f, 0.63357f, - 0.63482f, 0.63606f, 0.63730f, 0.63854f, - 0.63977f, 0.64100f, 0.64222f, 0.64344f, - 0.64466f, 0.64587f, 0.64708f, 0.64829f, - 0.64949f, 0.65069f, 0.65188f, 0.65307f, - 0.65426f, 0.65544f, 0.65662f, 0.65779f, - 0.65897f, 0.66013f, 0.66130f, 0.66246f, - 0.66362f, 0.66477f, 0.66592f, 0.66707f, - 0.66821f, 0.66935f, 0.67048f, 0.67162f, - 0.67275f, 0.67387f, 0.67499f, 0.67611f, - 0.67723f, 0.67834f, 0.67945f, 0.68055f, - 0.68165f, 0.68275f, 0.68385f, 0.68494f, - 0.68603f, 0.68711f, 0.68819f, 0.68927f, - 0.69035f, 0.69142f, 0.69249f, 0.69355f, - 0.69461f, 0.69567f, 0.69673f, 0.69778f, - 0.69883f, 0.69988f, 0.70092f, 0.70196f, - 0.70300f, 0.70403f, 0.70506f, 0.70609f, - 0.70711f, 0.70813f, 0.70915f, 0.71017f, - 0.71118f, 0.71219f, 0.71319f, 0.71420f, - 0.71520f, 0.71620f, 0.71719f, 0.71818f, - 0.71917f, 0.72016f, 0.72114f, 0.72212f, - 0.72309f, 0.72407f, 0.72504f, 0.72601f, - 0.72697f, 0.72794f, 0.72890f, 0.72985f, - 0.73081f, 0.73176f, 0.73271f, 0.73365f, - 0.73460f, 0.73554f, 0.73647f, 0.73741f, - 0.73834f, 0.73927f, 0.74020f, 0.74112f, - 0.74204f, 0.74296f, 0.74388f, 0.74479f, - 0.74570f, 0.74661f, 0.74751f, 0.74842f, - 0.74932f, 0.75021f, 0.75111f, 0.75200f, - 0.75289f, 0.75378f, 0.75466f, 0.75555f, - 0.75643f, 0.75730f, 0.75818f, 0.75905f, - 0.75992f, 0.76079f, 0.76165f, 0.76251f, - 0.76337f, 0.76423f, 0.76508f, 0.76594f, - 0.76679f, 0.76763f, 0.76848f, 0.76932f, - 0.77016f, 0.77100f, 0.77183f, 0.77267f, - 0.77350f, 0.77432f, 0.77515f, 0.77597f, - 0.77680f, 0.77761f, 0.77843f, 0.77924f, - 0.78006f, 0.78087f, 0.78167f, 0.78248f, - 0.78328f, 0.78408f, 0.78488f, 0.78568f, - 0.78647f, 0.78726f, 0.78805f, 0.78884f, - 0.78962f, 0.79040f, 0.79118f, 0.79196f, - 0.79274f, 0.79351f, 0.79428f, 0.79505f, - 0.79582f, 0.79658f, 0.79735f, 0.79811f, - 0.79887f, 0.79962f, 0.80038f, 0.80113f, - 0.80188f, 0.80263f, 0.80337f, 0.80412f, - 0.80486f, 0.80560f, 0.80634f, 0.80707f, - 0.80780f, 0.80854f, 0.80926f, 0.80999f, - 0.81072f, 0.81144f, 0.81216f, 0.81288f, - 0.81360f, 0.81431f, 0.81503f, 0.81574f, - 0.81645f, 0.81715f, 0.81786f, 0.81856f, - 0.81926f, 0.81996f, 0.82066f, 0.82135f, - 0.82205f, 0.82274f, 0.82343f, 0.82412f, - 0.82480f, 0.82549f, 0.82617f, 0.82685f, - 0.82753f, 0.82820f, 0.82888f, 0.82955f, - 0.83022f, 0.83089f, 0.83155f, 0.83222f, - 0.83288f, 0.83354f, 0.83420f, 0.83486f, - 0.83552f, 0.83617f, 0.83682f, 0.83747f, - 0.83812f, 0.83877f, 0.83941f, 0.84005f, - 0.84069f, 0.84133f, 0.84197f, 0.84261f, - 0.84324f, 0.84387f, 0.84450f, 0.84513f, - 0.84576f, 0.84639f, 0.84701f, 0.84763f, - 0.84825f, 0.84887f, 0.84949f, 0.85010f, - 0.85071f, 0.85132f, 0.85193f, 0.85254f, - 0.85315f, 0.85375f, 0.85436f, 0.85496f, - 0.85556f, 0.85615f, 0.85675f, 0.85735f, - 0.85794f, 0.85853f, 0.85912f, 0.85971f, - 0.86029f, 0.86088f, 0.86146f, 0.86204f, - 0.86262f, 0.86320f, 0.86378f, 0.86435f, - 0.86493f, 0.86550f, 0.86607f, 0.86664f, - 0.86720f, 0.86777f, 0.86833f, 0.86889f, - 0.86945f, 0.87001f, 0.87057f, 0.87113f, - 0.87168f, 0.87223f, 0.87278f, 0.87333f, - 0.87388f, 0.87443f, 0.87497f, 0.87552f, - 0.87606f, 0.87660f, 0.87714f, 0.87768f, - 0.87821f, 0.87875f, 0.87928f, 0.87981f, - 0.88034f, 0.88087f, 0.88140f, 0.88192f, - 0.88244f, 0.88297f, 0.88349f, 0.88401f, - 0.88453f, 0.88504f, 0.88556f, 0.88607f, - 0.88658f, 0.88709f, 0.88760f, 0.88811f, - 0.88862f, 0.88912f, 0.88963f, 0.89013f, - 0.89063f, 0.89113f, 0.89163f, 0.89212f, - 0.89262f, 0.89311f, 0.89360f, 0.89409f, - 0.89458f, 0.89507f, 0.89556f, 0.89604f, - 0.89653f, 0.89701f, 0.89749f, 0.89797f, - 0.89845f, 0.89892f, 0.89940f, 0.89987f, - 0.90035f, 0.90082f, 0.90129f, 0.90176f, - 0.90222f, 0.90269f, 0.90316f, 0.90362f, - 0.90408f, 0.90454f, 0.90500f, 0.90546f, - 0.90592f, 0.90637f, 0.90683f, 0.90728f, - 0.90773f, 0.90818f, 0.90863f, 0.90908f, - 0.90952f, 0.90997f, 0.91041f, 0.91085f, - 0.91130f, 0.91173f, 0.91217f, 0.91261f, - 0.91305f, 0.91348f, 0.91392f, 0.91435f, - 0.91478f, 0.91521f, 0.91564f, 0.91606f, - 0.91649f, 0.91691f, 0.91734f, 0.91776f, - 0.91818f, 0.91860f, 0.91902f, 0.91944f, - 0.91985f, 0.92027f, 0.92068f, 0.92109f, - 0.92150f, 0.92191f, 0.92232f, 0.92273f, - 0.92314f, 0.92354f, 0.92395f, 0.92435f, - 0.92475f, 0.92515f, 0.92555f, 0.92595f, - 0.92634f, 0.92674f, 0.92713f, 0.92753f, - 0.92792f, 0.92831f, 0.92870f, 0.92909f, - 0.92947f, 0.92986f, 0.93025f, 0.93063f, - 0.93101f, 0.93139f, 0.93177f, 0.93215f, - 0.93253f, 0.93291f, 0.93328f, 0.93366f, - 0.93403f, 0.93440f, 0.93478f, 0.93515f, - 0.93551f, 0.93588f, 0.93625f, 0.93661f, - 0.93698f, 0.93734f, 0.93770f, 0.93807f, - 0.93843f, 0.93878f, 0.93914f, 0.93950f, - 0.93986f, 0.94021f, 0.94056f, 0.94092f, - 0.94127f, 0.94162f, 0.94197f, 0.94231f, - 0.94266f, 0.94301f, 0.94335f, 0.94369f, - 0.94404f, 0.94438f, 0.94472f, 0.94506f, - 0.94540f, 0.94573f, 0.94607f, 0.94641f, - 0.94674f, 0.94707f, 0.94740f, 0.94774f, - 0.94807f, 0.94839f, 0.94872f, 0.94905f, - 0.94937f, 0.94970f, 0.95002f, 0.95035f, - 0.95067f, 0.95099f, 0.95131f, 0.95163f, - 0.95194f, 0.95226f, 0.95257f, 0.95289f, - 0.95320f, 0.95351f, 0.95383f, 0.95414f, - 0.95445f, 0.95475f, 0.95506f, 0.95537f, - 0.95567f, 0.95598f, 0.95628f, 0.95658f, - 0.95688f, 0.95718f, 0.95748f, 0.95778f, - 0.95808f, 0.95838f, 0.95867f, 0.95897f, - 0.95926f, 0.95955f, 0.95984f, 0.96013f, - 0.96042f, 0.96071f, 0.96100f, 0.96129f, - 0.96157f, 0.96186f, 0.96214f, 0.96242f, - 0.96271f, 0.96299f, 0.96327f, 0.96355f, - 0.96382f, 0.96410f, 0.96438f, 0.96465f, - 0.96493f, 0.96520f, 0.96547f, 0.96574f, - 0.96602f, 0.96629f, 0.96655f, 0.96682f, - 0.96709f, 0.96735f, 0.96762f, 0.96788f, - 0.96815f, 0.96841f, 0.96867f, 0.96893f, - 0.96919f, 0.96945f, 0.96971f, 0.96996f, - 0.97022f, 0.97047f, 0.97073f, 0.97098f, - 0.97123f, 0.97149f, 0.97174f, 0.97199f, - 0.97223f, 0.97248f, 0.97273f, 0.97297f, - 0.97322f, 0.97346f, 0.97371f, 0.97395f, - 0.97419f, 0.97443f, 0.97467f, 0.97491f, - 0.97515f, 0.97539f, 0.97562f, 0.97586f, - 0.97609f, 0.97633f, 0.97656f, 0.97679f, - 0.97702f, 0.97725f, 0.97748f, 0.97771f, - 0.97794f, 0.97817f, 0.97839f, 0.97862f, - 0.97884f, 0.97907f, 0.97929f, 0.97951f, - 0.97973f, 0.97995f, 0.98017f, 0.98039f, - 0.98061f, 0.98082f, 0.98104f, 0.98125f, - 0.98147f, 0.98168f, 0.98189f, 0.98211f, - 0.98232f, 0.98253f, 0.98274f, 0.98295f, - 0.98315f, 0.98336f, 0.98357f, 0.98377f, - 0.98398f, 0.98418f, 0.98438f, 0.98458f, - 0.98478f, 0.98498f, 0.98518f, 0.98538f, - 0.98558f, 0.98578f, 0.98597f, 0.98617f, - 0.98636f, 0.98656f, 0.98675f, 0.98694f, - 0.98714f, 0.98733f, 0.98752f, 0.98771f, - 0.98789f, 0.98808f, 0.98827f, 0.98845f, - 0.98864f, 0.98882f, 0.98901f, 0.98919f, - 0.98937f, 0.98955f, 0.98973f, 0.98991f, - 0.99009f, 0.99027f, 0.99045f, 0.99063f, - 0.99080f, 0.99098f, 0.99115f, 0.99133f, - 0.99150f, 0.99167f, 0.99184f, 0.99201f, - 0.99218f, 0.99235f, 0.99252f, 0.99269f, - 0.99285f, 0.99302f, 0.99319f, 0.99335f, - 0.99351f, 0.99368f, 0.99384f, 0.99400f, - 0.99416f, 0.99432f, 0.99448f, 0.99464f, - 0.99480f, 0.99495f, 0.99511f, 0.99527f, - 0.99542f, 0.99558f, 0.99573f, 0.99588f, - 0.99603f, 0.99619f, 0.99634f, 0.99649f, - 0.99664f, 0.99678f, 0.99693f, 0.99708f, - 0.99722f, 0.99737f, 0.99751f, 0.99766f, - 0.99780f, 0.99794f, 0.99809f, 0.99823f, - 0.99837f, 0.99851f, 0.99865f, 0.99879f, - 0.99892f, 0.99906f, 0.99920f, 0.99933f, - 0.99947f, 0.99960f, 0.99974f, 0.99987f, - 1.00000f -}; - -// This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here -static float sRGBGammaForward (const float x) { - if (x <= 0.0031308) - return x * 12.92; - else if (x > 1.0) - return 1.0 + (x - 1.0) * (1.055*(1.0/2.4)); // linear extension - else - return 1.055 * pow (x, 1.0 / 2.4) - 0.055; -} -static float sRGBGammaInverse (const float y) { - if (y <= 0.0031308 * 12.92) - return y * (1.0 / 12.92); - else if (y > 1.0) - return 1.0 + (y - 1.0) / (1.055*(1.0/2.4)); - else - return pow ((y + 0.055) * (1.0 / 1.055), 2.4); -} - -static void Invert3x3(const double (*A)[3], double (*B)[3]) { - - double a00 = A[0][0]; - double a01 = A[0][1]; - double a02 = A[0][2]; - double a10 = A[1][0]; - double a11 = A[1][1]; - double a12 = A[1][2]; - double a20 = A[2][0]; - double a21 = A[2][1]; - double a22 = A[2][2]; - double temp [3][3]; - - temp[0][0] = a11 * a22 - a21 * a12; - temp[0][1] = a21 * a02 - a01 * a22; - temp[0][2] = a01 * a12 - a11 * a02; - temp[1][0] = a20 * a12 - a10 * a22; - temp[1][1] = a00 * a22 - a20 * a02; - temp[1][2] = a10 * a02 - a00 * a12; - temp[2][0] = a10 * a21 - a20 * a11; - temp[2][1] = a20 * a01 - a00 * a21; - temp[2][2] = a00 * a11 - a10 * a01; - - double det = a00 * temp[0][0] + a01 * temp[1][0] + a02 * temp[2][0]; - - if (fabs(det) < 1.0E-10) { - abort(); // can't be inverted, we shouldn't be dealing with such matrices - } - - for (int j = 0; j < 3; j++) { - for (int k = 0; k < 3; k++) { - B[j][k] = temp[j][k] / det; - } - } -} - -static void Multiply3x3(const double (*A)[3], const double (*B)[3], double (*C)[3]) { - - // use temp to support having output same as input - double M[3][3]; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - M[i][j] = 0; - for (int k = 0; k < 3; k++) { - M[i][j] += A[i][k] * B[k][j]; - } - } - } - memcpy(C, M, 3 * 3 * sizeof(double)); -} - -static void Multiply3x3_v3(const double (*A)[3], const double B[3], double C[3]) { - - // use temp to support having output same as input - double M[3] = { 0, 0, 0 }; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - M[i] += A[i][j] * B[j]; - } - } - memcpy(C, M, 3 * sizeof(double)); -} - -static void Mix3x3(const double (*A)[3], double mulA, const double (*B)[3], double mulB, double (*C)[3]) { - - double M[3][3]; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - M[i][j] = A[i][j] * mulA + B[i][j] * mulB; - } - } - memcpy(C, M, 3 * 3 * sizeof(double)); -} - -static void MapWhiteMatrix(const double white1[3], const double white2[3], double (*B)[3]) { - - // code adapted from dng_color_spec::MapWhiteMatrix - - // Use the linearized Bradford adaptation matrix. - double Mb[3][3] = { { 0.8951, 0.2664, -0.1614 }, { -0.7502, 1.7135, 0.0367 }, { 0.0389, -0.0685, 1.0296 }}; - - double w1[3]; - Multiply3x3_v3(Mb, white1, w1); - double w2[3]; - Multiply3x3_v3(Mb, white2, w2); - - // Negative white coordinates are kind of meaningless. - w1[0] = std::max(w1[0], 0.0); - w1[1] = std::max(w1[1], 0.0); - w1[2] = std::max(w1[2], 0.0); - w2[0] = std::max(w2[0], 0.0); - w2[1] = std::max(w2[1], 0.0); - w2[2] = std::max(w2[2], 0.0); - - // Limit scaling to something reasonable. - double A[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - A[0][0] = std::max(0.1, std::min(w1[0] > 0.0 ? w2[0] / w1[0] : 10.0, 10.0)); - A[1][1] = std::max(0.1, std::min(w1[1] > 0.0 ? w2[1] / w1[1] : 10.0, 10.0)); - A[2][2] = std::max(0.1, std::min(w1[2] > 0.0 ? w2[2] / w1[2] : 10.0, 10.0)); - - double temp[3][3]; - Invert3x3(Mb, temp); - Multiply3x3(temp, A, temp); - Multiply3x3(temp, Mb, B); -} - -static void XYZtoXY(const double XYZ[3], double XY[2]) { - double X = XYZ[0]; - double Y = XYZ[1]; - double Z = XYZ[2]; - double total = X + Y + Z; - if (total > 0.0) { - XY[0] = X / total; - XY[1] = Y / total; - } else { - XY[0] = 0.3457; - XY[1] = 0.3585; - } -} - -static void XYtoXYZ(const double XY[2], double XYZ[3]) { - double temp[2] = { XY[0], XY[1] }; - // Restrict xy coord to someplace inside the range of real xy coordinates. - // This prevents math from doing strange things when users specify - // extreme temperature/tint coordinates. - temp[0] = std::max(0.000001, std::min(temp[0], 0.999999)); - temp[1] = std::max(0.000001, std::min(temp[1], 0.999999)); - if (temp[0] + temp[1] > 0.999999) { - double scale = 0.999999 / (temp[0] + temp[1]); - temp[0] *= scale; - temp[1] *= scale; - } - XYZ[0] = temp[0] / temp[1]; - XYZ[1] = 1.0; - XYZ[2] = (1.0 - temp[0] - temp[1]) / temp[1]; -} - -enum dngCalibrationIlluminant { - lsUnknown = 0, - lsDaylight = 1, - lsFluorescent = 2, - lsTungsten = 3, - lsFlash = 4, - lsFineWeather = 9, - lsCloudyWeather = 10, - lsShade = 11, - lsDaylightFluorescent = 12, // D 5700 - 7100K - lsDayWhiteFluorescent = 13, // N 4600 - 5500K - lsCoolWhiteFluorescent = 14, // W 3800 - 4500K - lsWhiteFluorescent = 15, // WW 3250 - 3800K - lsWarmWhiteFluorescent = 16, // L 2600 - 3250K - lsStandardLightA = 17, - lsStandardLightB = 18, - lsStandardLightC = 19, - lsD55 = 20, - lsD65 = 21, - lsD75 = 22, - lsD50 = 23, - lsISOStudioTungsten = 24, - lsOther = 255 -}; - -// should probably be moved to colortemp.cc -static double calibrationIlluminantToTemperature(int light) { - - // these temperatures are those found in DNG SDK reference code. - switch (light) { - case lsStandardLightA: - case lsTungsten: - return 2850.0; - case lsISOStudioTungsten: - return 3200.0; - case lsD50: - return 5000.0; - case lsD55: - case lsDaylight: - case lsFineWeather: - case lsFlash: - case lsStandardLightB: - return 5500.0; - case lsD65: - case lsStandardLightC: - case lsCloudyWeather: - return 6500.0; - case lsD75: - case lsShade: - return 7500.0; - case lsDaylightFluorescent: - return (5700.0 + 7100.0) * 0.5; - case lsDayWhiteFluorescent: - return (4600.0 + 5500.0) * 0.5; - case lsCoolWhiteFluorescent: - case lsFluorescent: - return (3800.0 + 4500.0) * 0.5; - case lsWhiteFluorescent: - return (3250.0 + 3800.0) * 0.5; - case lsWarmWhiteFluorescent: - return (2600.0 + 3250.0) * 0.5; - default: - return 0.0; - } -} -void DCPProfile::MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const -{ - // code adapted from dng_color_spec::FindXYZtoCamera - // note that we do not support monochrome or colorplanes > 3 (no reductionMatrix support) - // we do not support cameracalibration either - - double neutral[3]; // same as the DNG "AsShotNeutral" tag if white balance is Camera's own - { - /* A bit messy matrixing and conversions to get the neutral[] array from RT's own white balance which is stored in - sRGB space, while the DCP code needs multipliers in CameraRGB space */ - double r, g, b; - wb.getMultipliers(r, g, b); - - // camWbMatrix == imatrices.xyz_cam - double cam_xyz[3][3]; - Invert3x3(camWbMatrix, cam_xyz); - double cam_rgb[3][3]; - Multiply3x3(cam_xyz, xyz_sRGB, cam_rgb); - double camwb_red = cam_rgb[0][0]*r + cam_rgb[0][1]*g + cam_rgb[0][2]*b; - double camwb_green = cam_rgb[1][0]*r + cam_rgb[1][1]*g + cam_rgb[1][2]*b; - double camwb_blue = cam_rgb[2][0]*r + cam_rgb[2][1]*g + cam_rgb[2][2]*b; - neutral[0] = camwb_red / pre_mul[0]; - neutral[1] = camwb_green / pre_mul[1]; - neutral[2] = camwb_blue / pre_mul[2]; - double maxentry = 0; - for (int i = 0; i < 3; i++) { - if (neutral[i] > maxentry) { - maxentry = neutral[i]; - } - } - for (int i = 0; i < 3; i++) { - neutral[i] /= maxentry; - } - } - - /* Calculate what the RGB multipliers corresponds to as a white XY coordinate, based on the - DCP ColorMatrix or ColorMatrices if dual-illuminant. This is the DNG reference code way to - do it, which is a bit different from RT's own white balance model at the time of writing. - When RT's white balance can make use of the DCP color matrices we could use that instead. */ - double white_xy[2]; - dngref_NeutralToXY(neutral, preferredIlluminant, white_xy); - - bool hasFwd1 = hasForwardMatrix1; - bool hasFwd2 = hasForwardMatrix2; - bool hasCol1 = hasColorMatrix1; - bool hasCol2 = hasColorMatrix2; - if (preferredIlluminant == 1) { - if (hasFwd1) hasFwd2 = false; - if (hasCol1) hasCol2 = false; - } else if (preferredIlluminant == 2) { - if (hasFwd2) hasFwd1 = false; - if (hasCol2) hasCol1 = false; - } - - // mix if we have two matrices - double mix = 1.0; - if ((hasCol1 && hasCol2) || (hasFwd1 && hasFwd2)) { - double wbtemp; - /* DNG ref way to convert XY to temperature, which affect matrix mixing. A different model here - typically does not affect the result too much, ie it's probably not strictly necessary to - use the DNG reference code here, but we do it for now. */ - dngref_XYCoord2Temperature(white_xy, &wbtemp, NULL); - if (wbtemp <= temperature1) { - mix = 1.0; - } else if (wbtemp >= temperature2) { - mix = 0.0; - } else { - double invT = 1.0 / wbtemp; - mix = (invT - (1.0 / temperature2)) / ((1.0 / temperature1) - (1.0 / temperature2)); - } - } - - // Colormatrix - double mCol[3][3]; - if (hasCol1 && hasCol2) { - // interpolate - if (mix >= 1.0) { - memcpy(mCol, mColorMatrix1, sizeof(mCol)); - } else if (mix <= 0.0) { - memcpy(mCol, mColorMatrix2, sizeof(mCol)); - } else { - Mix3x3(mColorMatrix1, mix, mColorMatrix2, 1.0 - mix, mCol); - } - } else if (hasCol1) { - memcpy(mCol, mColorMatrix1, sizeof(mCol)); - } else { - memcpy(mCol, mColorMatrix2, sizeof(mCol)); - } - - /* - The exact position of the white XY coordinate affects the result very much, thus - it's important that the result is very similar or the same as DNG reference code. - Especially important is it that the raw-embedded "AsShot" multipliers is translated - to the same white XY coordinate as the DNG reference code, or else third party DCPs - will show incorrect color. - */ - - double white_xyz[3]; - XYtoXYZ(white_xy, white_xyz); - - double cam_xyz[3][3]; - if (hasFwd1 || hasFwd2) { - // always prefer ForwardMatrix ahead of ColorMatrix - double mFwd[3][3]; - if (hasFwd1 && hasFwd2) { - // interpolate - if (mix >= 1.0) { - memcpy(mFwd, mForwardMatrix1, sizeof(mFwd)); - } else if (mix <= 0.0) { - memcpy(mFwd, mForwardMatrix2, sizeof(mFwd)); - } else { - Mix3x3(mForwardMatrix1, mix, mForwardMatrix2, 1.0 - mix, mFwd); - } - } else if (hasFwd1) { - memcpy(mFwd, mForwardMatrix1, sizeof(mFwd)); - } else { - memcpy(mFwd, mForwardMatrix2, sizeof(mFwd)); - } - // adapted from dng_color_spec::SetWhiteXY - double CameraWhite[3]; - Multiply3x3_v3(mCol, white_xyz, CameraWhite); - - double whiteDiag[3][3] = {{CameraWhite[0], 0, 0}, {0, CameraWhite[1], 0}, {0, 0, CameraWhite[2]}}; - double whiteDiagInv[3][3]; - Invert3x3(whiteDiag, whiteDiagInv); - - double xyz_cam[3][3]; - Multiply3x3(mFwd, whiteDiagInv, xyz_cam); - Invert3x3(xyz_cam, cam_xyz); - } else { - double whiteMatrix[3][3]; - const double white_d50[3] = { 0.3457, 0.3585, 0.2958 }; // D50 - MapWhiteMatrix(white_d50, white_xyz, whiteMatrix); - Multiply3x3(mCol, whiteMatrix, cam_xyz); - } - - // convert cam_xyz (XYZ D50 to CameraRGB, "PCS to Camera" in DNG terminology) to mXYZCAM - - { - // This block can probably be simplified, seems unnecessary to pass through the sRGB matrix - // (probably dcraw legacy), it does no harm though as we don't clip anything. - int i,j,k; - - // Multiply out XYZ colorspace - double cam_rgb[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - for (i=0; i < 3; i++) - for (j=0; j < 3; j++) - for (k=0; k < 3; k++) - cam_rgb[i][j] += cam_xyz[i][k] * xyz_sRGB[k][j]; - - // Normalize cam_rgb so that: cam_rgb * (1,1,1) is (1,1,1,1) - double num; - for (i=0; i<3; i++) { - for (num=j=0; j<3; j++) num += cam_rgb[i][j]; - for (j=0; j<3; j++) cam_rgb[i][j] /= num; - } - - double rgb_cam[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - RawImageSource::inverse33 (cam_rgb, rgb_cam); - - for (i=0; i<3; i++) - for (j=0; j<3; j++) mXYZCAM[i][j]=0; - for (i=0; i<3; i++) - for (j=0; j<3; j++) - for (k=0; k<3; k++) - mXYZCAM[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; - } -} - -const DCPProfile::HSBModify* DCPProfile::MakeHueSatMap(ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const { - - *deleteHandle = NULL; - if (!aDeltas1) { - return NULL; - } - if (!aDeltas2) { - return aDeltas1; - } - - if (preferredIlluminant == 1) { - return aDeltas1; - } else if (preferredIlluminant == 2) { - return aDeltas2; - } - - // Interpolate based on color temperature. - if (temperature1 <= 0.0 || temperature2 <= 0.0 || temperature1 == temperature2) { - return aDeltas1; - } - bool reverseOrder = temperature1 > temperature2; - double t1, t2; - if (reverseOrder) { - t1 = temperature2; - t2 = temperature1; - } else { - t1 = temperature1; - t2 = temperature2; - } - - double mix; - if (wb.getTemp() <= t1) { - mix = 1.0; - } else if (wb.getTemp() >= t2) { - mix = 0.0; - } else { - double invT = 1.0 / wb.getTemp(); - mix = (invT - (1.0 / t2)) / ((1.0 / t1) - (1.0 / t2)); - } - - if (reverseOrder) { - mix = 1.0 - mix; - } - - if (mix >= 1.0) { - return aDeltas1; - } else if (mix <= 0.0) { - return aDeltas2; - } - - // Interpolate between the tables. - HSBModify *aDeltas = new HSBModify[DeltaInfo.iArrayCount]; - *deleteHandle = aDeltas; - float w1 = (float)mix; - float w2 = 1.0f - (float)mix; - for (int i = 0; i < DeltaInfo.iArrayCount; i++) { - aDeltas[i].fHueShift = w1 * aDeltas1[i].fHueShift + w2 * aDeltas2[i].fHueShift; - aDeltas[i].fSatScale = w1 * aDeltas1[i].fSatScale + w2 * aDeltas2[i].fSatScale; - aDeltas[i].fValScale = w1 * aDeltas1[i].fValScale + w2 * aDeltas2[i].fValScale; - } - return aDeltas; -} - -DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { - const int TIFFFloatSize=4; - const int TagColorMatrix1=50721, TagColorMatrix2=50722, TagProfileHueSatMapDims=50937; - const int TagForwardMatrix1=50964, TagForwardMatrix2=50965; - const int TagProfileHueSatMapData1=50938, TagProfileHueSatMapData2=50939; - const int TagCalibrationIlluminant1=50778, TagCalibrationIlluminant2=50779; - const int TagProfileLookTableData=50982, TagProfileLookTableDims=50981; // ProfileLookup is the low quality variant - const int TagProfileHueSatMapEncoding=51107, TagProfileLookTableEncoding=51108; - const int TagProfileToneCurve=50940, TagBaselineExposureOffset=51109; - const int TagProfileCopyright=50942; - - aDeltas1=aDeltas2=aLookTable=NULL; - - FILE *pFile = safe_g_fopen(fname, "rb"); - - TagDirectory *tagDir=ExifManager::parseTIFF(pFile, false); - - Tag* tag = tagDir->getTag(TagCalibrationIlluminant1); iLightSource1 = (tag!=NULL ? tag->toInt(0,rtexif::SHORT) : -1); - tag = tagDir->getTag(TagCalibrationIlluminant2); iLightSource2 = (tag!=NULL ? tag->toInt(0,rtexif::SHORT) : -1); - temperature1 = calibrationIlluminantToTemperature(iLightSource1); - temperature2 = calibrationIlluminantToTemperature(iLightSource2); - - bool hasSecondHueSat = tagDir->getTag(TagProfileHueSatMapData2)!=NULL; // some profiles have two matrices, but just one huesat - - // Fetch Forward Matrices, if any - hasForwardMatrix1 = false; - hasForwardMatrix2 = false; - hasColorMatrix1 = false; - hasColorMatrix2 = false; - hasToneCurve = false; - hasBaselineExposureOffset = false; - baselineExposureOffset = 0; - tag = tagDir->getTag(TagForwardMatrix1); - if (tag) { - hasForwardMatrix1 = true; - for (int row=0;row<3;row++) { - for (int col=0;col<3;col++) { - mForwardMatrix1[row][col]=(float)tag->toDouble((col+row*3)*8); - } - } - } - tag = tagDir->getTag(TagForwardMatrix2); - if (tag) { - hasForwardMatrix2 = true; - for (int row=0;row<3;row++) { - for (int col=0;col<3;col++) { - mForwardMatrix2[row][col]=(float)tag->toDouble((col+row*3)*8); - } - } - } - - // Color Matrix (1 is always there) - tag = tagDir->getTag(TagColorMatrix1); - if (!tag) { - // FIXME: better error handling - fprintf(stderr, "Bad DCP, no ColorMatrix1\n"); - abort(); - } - hasColorMatrix1 = true; - - for (int row=0;row<3;row++) { - for (int col=0;col<3;col++) { - mColorMatrix1[row][col]=(float)tag->toDouble((col+row*3)*8); - } - } - - tag=tagDir->getTag(TagProfileLookTableDims); - if (tag!=NULL) { - LookInfo.iHueDivisions=tag->toInt(0); LookInfo.iSatDivisions=tag->toInt(4); LookInfo.iValDivisions=tag->toInt(8); - - tag = tagDir->getTag(TagProfileLookTableEncoding); - LookInfo.sRGBGamma = tag != NULL && tag->toInt(0); - - tag = tagDir->getTag(TagProfileLookTableData); - LookInfo.iArrayCount = tag->getCount()/3; - - aLookTable =new HSBModify[LookInfo.iArrayCount]; - - for (int i=0;itoDouble((i*3)*TIFFFloatSize); - aLookTable[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize); - aLookTable[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize); - } - - // precalculated constants for table application - LookInfo.pc.hScale = (LookInfo.iHueDivisions < 2) ? 0.0f : (LookInfo.iHueDivisions * (1.0f / 6.0f)); - LookInfo.pc.sScale = (float) (LookInfo.iSatDivisions - 1); - LookInfo.pc.vScale = (float) (LookInfo.iValDivisions - 1); - LookInfo.pc.maxHueIndex0 = LookInfo.iHueDivisions - 1; - LookInfo.pc.maxSatIndex0 = LookInfo.iSatDivisions - 2; - LookInfo.pc.maxValIndex0 = LookInfo.iValDivisions - 2; - LookInfo.pc.hueStep = LookInfo.iSatDivisions; - LookInfo.pc.valStep = LookInfo.iHueDivisions * LookInfo.pc.hueStep; - } - - tag = tagDir->getTag(TagProfileHueSatMapDims); - if (tag!=NULL) { - DeltaInfo.iHueDivisions=tag->toInt(0); DeltaInfo.iSatDivisions=tag->toInt(4); DeltaInfo.iValDivisions=tag->toInt(8); - - tag = tagDir->getTag(TagProfileHueSatMapEncoding); - DeltaInfo.sRGBGamma = tag != NULL && tag->toInt(0); - - tag = tagDir->getTag(TagProfileHueSatMapData1); - DeltaInfo.iArrayCount = tag->getCount()/3; - - aDeltas1=new HSBModify[DeltaInfo.iArrayCount]; - - for (int i=0;itoDouble((i*3)*TIFFFloatSize); - aDeltas1[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize); - aDeltas1[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize); - } - - DeltaInfo.pc.hScale = (DeltaInfo.iHueDivisions < 2) ? 0.0f : (DeltaInfo.iHueDivisions * (1.0f / 6.0f)); - DeltaInfo.pc.sScale = (float) (DeltaInfo.iSatDivisions - 1); - DeltaInfo.pc.vScale = (float) (DeltaInfo.iValDivisions - 1); - DeltaInfo.pc.maxHueIndex0 = DeltaInfo.iHueDivisions - 1; - DeltaInfo.pc.maxSatIndex0 = DeltaInfo.iSatDivisions - 2; - DeltaInfo.pc.maxValIndex0 = DeltaInfo.iValDivisions - 2; - DeltaInfo.pc.hueStep = DeltaInfo.iSatDivisions; - DeltaInfo.pc.valStep = DeltaInfo.iHueDivisions * DeltaInfo.pc.hueStep; - } - - if (iLightSource2!=-1) { - // Second matrix - tag = tagDir->getTag(TagColorMatrix2); - hasColorMatrix2 = true; - - for (int row=0;row<3;row++) { - for (int col=0;col<3;col++) { - mColorMatrix2[row][col]= (tag!=NULL ? (float)tag->toDouble((col+row*3)*8) : mColorMatrix1[row][col]); - } - } - - // Second huesatmap - if (hasSecondHueSat) { - aDeltas2=new HSBModify[DeltaInfo.iArrayCount]; - - // Saturation maps. Need to be unwinded. - tag = tagDir->getTag(TagProfileHueSatMapData2); - - for (int i=0;itoDouble((i*3)*TIFFFloatSize); - aDeltas2[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize); - aDeltas2[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize); - } - } - } - - tag = tagDir->getTag(TagBaselineExposureOffset); - if (tag) { - hasBaselineExposureOffset = true; - baselineExposureOffset = tag->toDouble(); - } - - // Read tone curve points, if any, but disable to RTs own profiles - tag = tagDir->getTag(TagProfileToneCurve); - if (tag!=NULL && !isRTProfile) { - std::vector cPoints; - cPoints.push_back(double(DCT_Spline)); // The first value is the curve type - - // push back each X/Y coordinates in a loop - bool curve_is_linear = true; - for (int i=0;igetCount(); i+= 2) { - double x = tag->toDouble((i+0)*TIFFFloatSize); - double y = tag->toDouble((i+1)*TIFFFloatSize); - if (x != y) { - curve_is_linear = false; - } - cPoints.push_back( x ); - cPoints.push_back( y ); - } - - if (!curve_is_linear) { - // Create the curve - DiagonalCurve rawCurve(cPoints, CURVES_MIN_POLY_POINTS); - - toneCurve.Set((Curve*)&rawCurve); - hasToneCurve = true; - } - } else if (tag == NULL) { - tag = tagDir->getTag(TagProfileCopyright); - if (tag!=NULL && tag->valueToString().find("Adobe Systems") != std::string::npos) { - // an Adobe profile without tone curve is expected to have the Adobe Default Curve, we add that - std::vector cPoints; - cPoints.push_back(double(DCT_Spline)); - const size_t tc_len = sizeof(adobe_camera_raw_default_curve)/sizeof(adobe_camera_raw_default_curve[0]); - for (size_t i = 0; i < tc_len; i++) { - double x = (double)i / (tc_len - 1); - double y = (double)adobe_camera_raw_default_curve[i]; - cPoints.push_back( x ); - cPoints.push_back( y ); - } - DiagonalCurve rawCurve(cPoints, CURVES_MIN_POLY_POINTS); - toneCurve.Set((Curve*)&rawCurve); - hasToneCurve = true; - } - } - - willInterpolate = false; - if (hasForwardMatrix1) { - if (hasForwardMatrix2) { - if (memcmp(mForwardMatrix1, mForwardMatrix2, sizeof(mForwardMatrix1)) != 0) { - // common that forward matrices are the same! - willInterpolate = true; - } - if (aDeltas1 && aDeltas2) { - // we assume tables are different - willInterpolate = true; - } - } - } - if (hasColorMatrix1 && hasColorMatrix2) { - if (memcmp(mColorMatrix1, mColorMatrix2, sizeof(mColorMatrix1)) != 0) { - willInterpolate = true; - } - if (aDeltas1 && aDeltas2) { - willInterpolate = true; - } - } - - if (pFile!=NULL) fclose(pFile); - delete tagDir; -} - -DCPProfile::~DCPProfile() { - delete[] aDeltas1; - delete[] aDeltas2; - delete[] aLookTable; -} - -void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) const { - - // Apply the HueSatMap. Ported from Adobes reference implementation - float hueShift, satScale, valScale; - float vEncoded = v; - - if (ti.iValDivisions < 2) // Optimize most common case of "2.5D" table. - { - float hScaled = h * ti.pc.hScale; - float sScaled = s * ti.pc.sScale; - - int hIndex0 = max((int)hScaled, 0); - int sIndex0 = max(min((int)sScaled,ti.pc.maxSatIndex0),0); - - int hIndex1 = hIndex0 + 1; - - if (hIndex0 >= ti.pc.maxHueIndex0) - { - hIndex0 = ti.pc.maxHueIndex0; - hIndex1 = 0; - } - - float hFract1 = hScaled - (float) hIndex0; - float sFract1 = sScaled - (float) sIndex0; - - float hFract0 = 1.0f - hFract1; - float sFract0 = 1.0f - sFract1; - - const HSBModify *entry00 = tableBase + hIndex0 * ti.pc.hueStep + sIndex0; - const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep; - - float hueShift0 = hFract0 * entry00->fHueShift + hFract1 * entry01->fHueShift; - float satScale0 = hFract0 * entry00->fSatScale + hFract1 * entry01->fSatScale; - float valScale0 = hFract0 * entry00->fValScale + hFract1 * entry01->fValScale; - - entry00++; - entry01++; - - float hueShift1 = hFract0 * entry00->fHueShift + - hFract1 * entry01->fHueShift; - - float satScale1 = hFract0 * entry00->fSatScale + - hFract1 * entry01->fSatScale; - - float valScale1 = hFract0 * entry00->fValScale + - hFract1 * entry01->fValScale; - - hueShift = sFract0 * hueShift0 + sFract1 * hueShift1; - satScale = sFract0 * satScale0 + sFract1 * satScale1; - valScale = sFract0 * valScale0 + sFract1 * valScale1; - - } else { - - float hScaled = h * ti.pc.hScale; - float sScaled = s * ti.pc.sScale; - if (ti.sRGBGamma) vEncoded = sRGBGammaForward(v); - float vScaled = vEncoded * ti.pc.vScale; - - int hIndex0 = (int) hScaled; - int sIndex0 = max(min((int)sScaled,ti.pc.maxSatIndex0),0); - int vIndex0 = max(min((int)vScaled,ti.pc.maxValIndex0),0); - - int hIndex1 = hIndex0 + 1; - - if (hIndex0 >= ti.pc.maxHueIndex0) - { - hIndex0 = ti.pc.maxHueIndex0; - hIndex1 = 0; - } - - float hFract1 = hScaled - (float) hIndex0; - float sFract1 = sScaled - (float) sIndex0; - float vFract1 = vScaled - (float) vIndex0; - - float hFract0 = 1.0f - hFract1; - float sFract0 = 1.0f - sFract1; - float vFract0 = 1.0f - vFract1; - - const HSBModify *entry00 = tableBase + vIndex0 * ti.pc.valStep + hIndex0 * ti.pc.hueStep + sIndex0; - - const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep; - - const HSBModify *entry10 = entry00 + ti.pc.valStep; - const HSBModify *entry11 = entry01 + ti.pc.valStep; - - float hueShift0 = vFract0 * (hFract0 * entry00->fHueShift + - hFract1 * entry01->fHueShift) + - vFract1 * (hFract0 * entry10->fHueShift + - hFract1 * entry11->fHueShift); - - float satScale0 = vFract0 * (hFract0 * entry00->fSatScale + - hFract1 * entry01->fSatScale) + - vFract1 * (hFract0 * entry10->fSatScale + - hFract1 * entry11->fSatScale); - - float valScale0 = vFract0 * (hFract0 * entry00->fValScale + - hFract1 * entry01->fValScale) + - vFract1 * (hFract0 * entry10->fValScale + - hFract1 * entry11->fValScale); - - entry00++; - entry01++; - entry10++; - entry11++; - - float hueShift1 = vFract0 * (hFract0 * entry00->fHueShift + - hFract1 * entry01->fHueShift) + - vFract1 * (hFract0 * entry10->fHueShift + - hFract1 * entry11->fHueShift); - - float satScale1 = vFract0 * (hFract0 * entry00->fSatScale + - hFract1 * entry01->fSatScale) + - vFract1 * (hFract0 * entry10->fSatScale + - hFract1 * entry11->fSatScale); - - float valScale1 = vFract0 * (hFract0 * entry00->fValScale + - hFract1 * entry01->fValScale) + - vFract1 * (hFract0 * entry10->fValScale + - hFract1 * entry11->fValScale); - - hueShift = sFract0 * hueShift0 + sFract1 * hueShift1; - satScale = sFract0 * satScale0 + sFract1 * satScale1; - valScale = sFract0 * valScale0 + sFract1 * valScale1; - } - - hueShift *= (6.0f / 360.0f); // Convert to internal hue range. - - h += hueShift; - s *= satScale; // no clipping here, we are RT float :-) - if (ti.sRGBGamma) { - v = sRGBGammaInverse(vEncoded * valScale); - } else { - v *= valScale; - } -} - -struct ruvt { - double r; - double u; - double v; - double t; -}; - -static const double kTintScale = -3000.0; -static const ruvt kTempTable [] = - { - { 0, 0.18006, 0.26352, -0.24341 }, - { 10, 0.18066, 0.26589, -0.25479 }, - { 20, 0.18133, 0.26846, -0.26876 }, - { 30, 0.18208, 0.27119, -0.28539 }, - { 40, 0.18293, 0.27407, -0.30470 }, - { 50, 0.18388, 0.27709, -0.32675 }, - { 60, 0.18494, 0.28021, -0.35156 }, - { 70, 0.18611, 0.28342, -0.37915 }, - { 80, 0.18740, 0.28668, -0.40955 }, - { 90, 0.18880, 0.28997, -0.44278 }, - { 100, 0.19032, 0.29326, -0.47888 }, - { 125, 0.19462, 0.30141, -0.58204 }, - { 150, 0.19962, 0.30921, -0.70471 }, - { 175, 0.20525, 0.31647, -0.84901 }, - { 200, 0.21142, 0.32312, -1.0182 }, - { 225, 0.21807, 0.32909, -1.2168 }, - { 250, 0.22511, 0.33439, -1.4512 }, - { 275, 0.23247, 0.33904, -1.7298 }, - { 300, 0.24010, 0.34308, -2.0637 }, - { 325, 0.24702, 0.34655, -2.4681 }, - { 350, 0.25591, 0.34951, -2.9641 }, - { 375, 0.26400, 0.35200, -3.5814 }, - { 400, 0.27218, 0.35407, -4.3633 }, - { 425, 0.28039, 0.35577, -5.3762 }, - { 450, 0.28863, 0.35714, -6.7262 }, - { 475, 0.29685, 0.35823, -8.5955 }, - { 500, 0.30505, 0.35907, -11.324 }, - { 525, 0.31320, 0.35968, -15.628 }, - { 550, 0.32129, 0.36011, -23.325 }, - { 575, 0.32931, 0.36038, -40.770 }, - { 600, 0.33724, 0.36051, -116.45 } - }; - -void DCPProfile::dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const { - double fTemperature = 0; - double fTint = 0; - - // Convert to uv space. - double u = 2.0 * whiteXY[0] / (1.5 - whiteXY[0] + 6.0 * whiteXY[1]); - double v = 3.0 * whiteXY[1] / (1.5 - whiteXY[0] + 6.0 * whiteXY[1]); - - // Search for line pair coordinate is between. - double last_dt = 0.0; - double last_dv = 0.0; - double last_du = 0.0; - - for (uint32_t index = 1; index <= 30; index++) { - // Convert slope to delta-u and delta-v, with length 1. - double du = 1.0; - double dv = kTempTable [index] . t; - double len = sqrt (1.0 + dv * dv); - du /= len; - dv /= len; - - // Find delta from black body point to test coordinate. - double uu = u - kTempTable [index] . u; - double vv = v - kTempTable [index] . v; - - // Find distance above or below line. - double dt = - uu * dv + vv * du; - - // If below line, we have found line pair. - if (dt <= 0.0 || index == 30) { - // Find fractional weight of two lines. - if (dt > 0.0) - dt = 0.0; - dt = -dt; - double f; - if (index == 1) - { - f = 0.0; - } - else - { - f = dt / (last_dt + dt); - } - - // Interpolate the temperature. - fTemperature = 1.0E6 / (kTempTable [index - 1] . r * f + - kTempTable [index ] . r * (1.0 - f)); - - // Find delta from black body point to test coordinate. - uu = u - (kTempTable [index - 1] . u * f + - kTempTable [index ] . u * (1.0 - f)); - vv = v - (kTempTable [index - 1] . v * f + - kTempTable [index ] . v * (1.0 - f)); - // Interpolate vectors along slope. - du = du * (1.0 - f) + last_du * f; - dv = dv * (1.0 - f) + last_dv * f; - len = sqrt (du * du + dv * dv); - du /= len; - dv /= len; - - // Find distance along slope. - fTint = (uu * du + vv * dv) * kTintScale; - break; - } - // Try next line pair. - last_dt = dt; - last_du = du; - last_dv = dv; - } - if (temp != NULL) - *temp = fTemperature; - if (tint != NULL) - *tint = fTint; -} - -void DCPProfile::dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const { - - bool hasCol1 = hasColorMatrix1; - bool hasCol2 = hasColorMatrix2; - if (preferredIlluminant == 1) { - if (hasCol1) hasCol2 = false; - } else if (preferredIlluminant == 2) { - if (hasCol2) hasCol1 = false; - } - - // mix if we have two matrices - double mix; - if (hasCol1 && hasCol2) { - double wbtemp; - /* - Note: we're using DNG SDK reference code for XY to temperature translation to get the exact same mix as - the reference code does. - */ - dngref_XYCoord2Temperature(whiteXY, &wbtemp, NULL); - if (wbtemp <= temperature1) { - mix = 1.0; - } else if (wbtemp >= temperature2) { - mix = 0.0; - } else { - double invT = 1.0 / wbtemp; - mix = (invT - (1.0 / temperature2)) / ((1.0 / temperature1) - (1.0 / temperature2)); - } - } - - // Interpolate the color matrix. - double mCol[3][3]; - if (hasCol1 && hasCol2) { - // interpolate - if (mix >= 1.0) { - memcpy(mCol, mColorMatrix1, sizeof(mCol)); - } else if (mix <= 0.0) { - memcpy(mCol, mColorMatrix2, sizeof(mCol)); - } else { - Mix3x3(mColorMatrix1, mix, mColorMatrix2, 1.0 - mix, mCol); - } - } else if (hasCol1) { - memcpy(mCol, mColorMatrix1, sizeof(mCol)); - } else { - memcpy(mCol, mColorMatrix2, sizeof(mCol)); - } - memcpy(xyzToCamera, mCol, sizeof(mCol)); -} - -void DCPProfile::dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const { - const int kMaxPasses = 30; - double lastXY[2] = { 0.3457, 0.3585 }; // D50 - for (int pass = 0; pass < kMaxPasses; pass++) { - double xyzToCamera[3][3]; - dngref_FindXYZtoCamera(lastXY, preferredIlluminant, xyzToCamera); - - double invM[3][3], nextXYZ[3], nextXY[2]; - Invert3x3(xyzToCamera, invM); - Multiply3x3_v3(invM, neutral, nextXYZ); - XYZtoXY(nextXYZ, nextXY); - - if (fabs(nextXY[0] - lastXY[0]) + - fabs(nextXY[1] - lastXY[1]) < 0.0000001) - { - XY[0] = nextXY[0]; - XY[1] = nextXY[1]; - return; - } - // If we reach the limit without converging, we are most likely - // in a two value oscillation. So take the average of the last - // two estimates and give up. - if (pass == kMaxPasses - 1) { - nextXY[0] = (lastXY[0] + nextXY[0]) * 0.5; - nextXY[1] = (lastXY[1] + nextXY[1]) * 0.5; - } - lastXY[0] = nextXY[0]; - lastXY[1] = nextXY[1]; - } - XY[0] = lastXY[0]; - XY[1] = lastXY[1]; -} - -void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], bool useToneCurve, bool applyHueSatMap, bool applyLookTable) const { - - TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); - - double mXYZCAM[3][3]; // Camera RGB to XYZ D50 matrix - MakeXYZCAM(wb, pre_mul, camWbMatrix, preferredIlluminant, mXYZCAM); - HSBModify *deleteTableHandle; - const HSBModify *deltaBase = MakeHueSatMap(wb, preferredIlluminant, &deleteTableHandle); - if (!deltaBase) applyHueSatMap = false; - if (!aLookTable) applyLookTable = false; - - useToneCurve&=toneCurve; - - if (!applyHueSatMap && !applyLookTable && !useToneCurve) { - //===== The fast path: no LUT and not tone curve- Calculate matrix for direct conversion raw>working space - double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - for (int k=0; k<3; k++) - mat[i][j] += mWork[i][k] * mXYZCAM[k][j]; - - // Apply the matrix part -#pragma omp parallel for - for (int y=0; yheight; y++) { - float newr, newg, newb; - for (int x=0; xwidth; x++) { - newr = mat[0][0]*pImg->r(y,x) + mat[0][1]*pImg->g(y,x) + mat[0][2]*pImg->b(y,x); - newg = mat[1][0]*pImg->r(y,x) + mat[1][1]*pImg->g(y,x) + mat[1][2]*pImg->b(y,x); - newb = mat[2][0]*pImg->r(y,x) + mat[2][1]*pImg->g(y,x) + mat[2][2]*pImg->b(y,x); - - pImg->r(y,x) = newr; pImg->g(y,x) = newg; pImg->b(y,x) = newb; - } - } - } - else { - //===== LUT available- Calculate matrix for conversion raw>ProPhoto - double m2ProPhoto[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - for (int k=0; k<3; k++) - m2ProPhoto[i][j] += prophoto_xyz[i][k] * mXYZCAM[k][j]; - - double m2Work[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - for (int k=0; k<3; k++) - m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; - - // Convert to prophoto and apply LUT -#pragma omp parallel for - for (int y=0; yheight; y++) { - float newr, newg, newb, h,s,v,hs,ss,vs; - for (int x=0; xwidth; x++) { - newr = m2ProPhoto[0][0]*pImg->r(y,x) + m2ProPhoto[0][1]*pImg->g(y,x) + m2ProPhoto[0][2]*pImg->b(y,x); - newg = m2ProPhoto[1][0]*pImg->r(y,x) + m2ProPhoto[1][1]*pImg->g(y,x) + m2ProPhoto[1][2]*pImg->b(y,x); - newb = m2ProPhoto[2][0]*pImg->r(y,x) + m2ProPhoto[2][1]*pImg->g(y,x) + m2ProPhoto[2][2]*pImg->b(y,x); - - // if point is in negative area, just the matrix, but not the LUT - if ((applyHueSatMap || applyLookTable) && newr>=0 && newg>=0 && newb>=0) { - Color::rgb2hsv(newr, newg, newb, h , s, v); - h*=6.f; // RT calculates in [0,1] - - if (applyHueSatMap) { - HSDApply(DeltaInfo, deltaBase, h, s, v); - } - if (applyLookTable) { - HSDApply(LookInfo, aLookTable, h, s, v); - } - - // RT range correction - if (h < 0.0f) h += 6.0f; - if (h >= 6.0f) h -= 6.0f; - h/=6.f; - Color::hsv2rgb( h, s, v, newr, newg, newb); - } - // tone curve - if (useToneCurve) toneCurve.Apply(newr, newg, newb); - - pImg->r(y,x) = m2Work[0][0]*newr + m2Work[0][1]*newg + m2Work[0][2]*newb; - pImg->g(y,x) = m2Work[1][0]*newr + m2Work[1][1]*newg + m2Work[1][2]*newb; - pImg->b(y,x) = m2Work[2][0]*newr + m2Work[2][1]*newg + m2Work[2][2]*newb; - } - } - } - - if (deleteTableHandle) delete[] deleteTableHandle; -} - -void DCPProfile::setStep2ApplyState(Glib::ustring workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure) { - - applyState.useToneCurve = useToneCurve; - applyState.applyLookTable = applyLookTable; - applyState.blScale = 1.0; - if (!aLookTable) applyState.applyLookTable = false; - if (!hasToneCurve) applyState.useToneCurve = false; - if (hasBaselineExposureOffset && applyBaselineExposure) { - applyState.blScale = powf(2, baselineExposureOffset); - } - - if (workingSpace == "ProPhoto") { - applyState.alreadyProPhoto = true; - } else { - applyState.alreadyProPhoto = false; - TMatrix mWork; - - mWork = iccStore->workingSpaceMatrix (workingSpace); - memset(applyState.m2ProPhoto, 0, sizeof(applyState.m2ProPhoto)); - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - for (int k=0; k<3; k++) - applyState.m2ProPhoto[i][j] += prophoto_xyz[i][k] * mWork[k][j]; - - mWork = iccStore->workingSpaceInverseMatrix (workingSpace); - memset(applyState.m2Work, 0, sizeof(applyState.m2Work)); - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - for (int k=0; k<3; k++) - applyState.m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; - } -} - -void DCPProfile::step2ApplyTile(float *rc, float *gc, float *bc, int width, int height, int tileWidth) const { - -#define FCLIP(a) ((a)>0.0?((a)<65535.5?(a):65535.5):0.0) -#define CLIP01(a) ((a)>0?((a)<1?(a):1):0) - - float exp_scale = 1.0; - exp_scale *= applyState.blScale; - if (!applyState.useToneCurve && !applyState.applyLookTable) { - if (exp_scale == 1.0) { - return; - } - for (int y=0; y= 6.0f) h -= 6.0f; - h/=6.f; - Color::hsv2rgb( h, s, v, newr, newg, newb); - } - if (applyState.useToneCurve) { - toneCurve.Apply(newr, newg, newb); - } - - if (applyState.alreadyProPhoto) { - rc[y*tileWidth+x] = newr; - gc[y*tileWidth+x] = newg; - bc[y*tileWidth+x] = newb; - } else { - rc[y*tileWidth+x] = applyState.m2Work[0][0]*newr + applyState.m2Work[0][1]*newg + applyState.m2Work[0][2]*newb; - gc[y*tileWidth+x] = applyState.m2Work[1][0]*newr + applyState.m2Work[1][1]*newg + applyState.m2Work[1][2]*newb; - bc[y*tileWidth+x] = applyState.m2Work[2][0]*newr + applyState.m2Work[2][1]*newg + applyState.m2Work[2][2]*newb; - } - } - } - } -} - -// Generates as singleton -DCPStore* DCPStore::getInstance() -{ - static DCPStore* instance_ = 0; - if ( instance_ == 0 ) - { - static MyMutex smutex_; - MyMutex::MyLock lock(smutex_); - if ( instance_ == 0 ) - { - instance_ = new DCPStore(); - } - } - return instance_; -} - -// Reads all profiles from the given profiles dir -void DCPStore::init (Glib::ustring rtProfileDir) { - MyMutex::MyLock lock(mtx); - - fileStdProfiles.clear(); - - Glib::ustring rootDirName=rtProfileDir; - - if (rootDirName!="") { - std::deque qDirs; - - qDirs.push_front(rootDirName); - - while (!qDirs.empty()) { - // process directory - Glib::ustring dirname = qDirs.back(); - qDirs.pop_back(); - - Glib::Dir* dir = NULL; - try { - if (!safe_file_test (dirname, Glib::FILE_TEST_IS_DIR)) return; - dir = new Glib::Dir (dirname); - } - catch (Glib::Exception& fe) { - return; - } - dirname = dirname + "/"; - for (Glib::DirIterator i = dir->begin(); i!=dir->end(); ++i) { - Glib::ustring fname = dirname + *i; - Glib::ustring sname = *i; - // ignore directories - if (!safe_file_test (fname, Glib::FILE_TEST_IS_DIR)) { - size_t lastdot = sname.find_last_of ('.'); - if (lastdot!=Glib::ustring::npos && lastdot<=sname.size()-4 && (!sname.casefold().compare (lastdot, 4, ".dcp"))) { - Glib::ustring camShortName = sname.substr(0,lastdot).uppercase(); - fileStdProfiles[camShortName]=fname; // they will be loaded and cached on demand - } - } else qDirs.push_front(fname); // for later scanning - } - delete dir; - } - } -} - -DCPProfile* DCPStore::getProfile (Glib::ustring filename, bool isRTProfile) { - MyMutex::MyLock lock(mtx); - - std::map::iterator r = profileCache.find (filename); - if (r!=profileCache.end()) return r->second; - - // Add profile - profileCache[filename]=new DCPProfile(filename, isRTProfile); - - return profileCache[filename]; -} - -DCPProfile* DCPStore::getStdProfile(Glib::ustring camShortName) { - Glib::ustring name2=camShortName.uppercase(); - - // Warning: do NOT use map.find(), since it does not seem to work reliably here - for (std::map::iterator i=fileStdProfiles.begin();i!=fileStdProfiles.end();i++) - if (name2==(*i).first) return getProfile((*i).second, true); - - return NULL; -} - -bool DCPStore::isValidDCPFileName(Glib::ustring filename) const { - if (!safe_file_test (filename, Glib::FILE_TEST_EXISTS) || safe_file_test (filename, Glib::FILE_TEST_IS_DIR)) return false; - size_t pos=filename.find_last_of ('.'); - return pos>0 && (!filename.casefold().compare (pos, 4, ".dcp") || !filename.casefold().compare (pos, 4, ".dng")); -} +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2012 Oliver Duis +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ +#include + +#include "dcp.h" +#include "safegtk.h" +#include "iccmatrices.h" +#include "iccstore.h" +#include "rawimagesource.h" +#include "improcfun.h" +#include "rt_math.h" + +using namespace std; +using namespace rtengine; +using namespace rtexif; + +static const float adobe_camera_raw_default_curve[] = { + 0.00000f, 0.00078f, 0.00160f, 0.00242f, + 0.00314f, 0.00385f, 0.00460f, 0.00539f, + 0.00623f, 0.00712f, 0.00806f, 0.00906f, + 0.01012f, 0.01122f, 0.01238f, 0.01359f, + 0.01485f, 0.01616f, 0.01751f, 0.01890f, + 0.02033f, 0.02180f, 0.02331f, 0.02485f, + 0.02643f, 0.02804f, 0.02967f, 0.03134f, + 0.03303f, 0.03475f, 0.03648f, 0.03824f, + 0.04002f, 0.04181f, 0.04362f, 0.04545f, + 0.04730f, 0.04916f, 0.05103f, 0.05292f, + 0.05483f, 0.05675f, 0.05868f, 0.06063f, + 0.06259f, 0.06457f, 0.06655f, 0.06856f, + 0.07057f, 0.07259f, 0.07463f, 0.07668f, + 0.07874f, 0.08081f, 0.08290f, 0.08499f, + 0.08710f, 0.08921f, 0.09134f, 0.09348f, + 0.09563f, 0.09779f, 0.09996f, 0.10214f, + 0.10433f, 0.10652f, 0.10873f, 0.11095f, + 0.11318f, 0.11541f, 0.11766f, 0.11991f, + 0.12218f, 0.12445f, 0.12673f, 0.12902f, + 0.13132f, 0.13363f, 0.13595f, 0.13827f, + 0.14061f, 0.14295f, 0.14530f, 0.14765f, + 0.15002f, 0.15239f, 0.15477f, 0.15716f, + 0.15956f, 0.16197f, 0.16438f, 0.16680f, + 0.16923f, 0.17166f, 0.17410f, 0.17655f, + 0.17901f, 0.18148f, 0.18395f, 0.18643f, + 0.18891f, 0.19141f, 0.19391f, 0.19641f, + 0.19893f, 0.20145f, 0.20398f, 0.20651f, + 0.20905f, 0.21160f, 0.21416f, 0.21672f, + 0.21929f, 0.22185f, 0.22440f, 0.22696f, + 0.22950f, 0.23204f, 0.23458f, 0.23711f, + 0.23963f, 0.24215f, 0.24466f, 0.24717f, + 0.24967f, 0.25216f, 0.25465f, 0.25713f, + 0.25961f, 0.26208f, 0.26454f, 0.26700f, + 0.26945f, 0.27189f, 0.27433f, 0.27676f, + 0.27918f, 0.28160f, 0.28401f, 0.28641f, + 0.28881f, 0.29120f, 0.29358f, 0.29596f, + 0.29833f, 0.30069f, 0.30305f, 0.30540f, + 0.30774f, 0.31008f, 0.31241f, 0.31473f, + 0.31704f, 0.31935f, 0.32165f, 0.32395f, + 0.32623f, 0.32851f, 0.33079f, 0.33305f, + 0.33531f, 0.33756f, 0.33981f, 0.34205f, + 0.34428f, 0.34650f, 0.34872f, 0.35093f, + 0.35313f, 0.35532f, 0.35751f, 0.35969f, + 0.36187f, 0.36404f, 0.36620f, 0.36835f, + 0.37050f, 0.37264f, 0.37477f, 0.37689f, + 0.37901f, 0.38112f, 0.38323f, 0.38533f, + 0.38742f, 0.38950f, 0.39158f, 0.39365f, + 0.39571f, 0.39777f, 0.39982f, 0.40186f, + 0.40389f, 0.40592f, 0.40794f, 0.40996f, + 0.41197f, 0.41397f, 0.41596f, 0.41795f, + 0.41993f, 0.42191f, 0.42388f, 0.42584f, + 0.42779f, 0.42974f, 0.43168f, 0.43362f, + 0.43554f, 0.43747f, 0.43938f, 0.44129f, + 0.44319f, 0.44509f, 0.44698f, 0.44886f, + 0.45073f, 0.45260f, 0.45447f, 0.45632f, + 0.45817f, 0.46002f, 0.46186f, 0.46369f, + 0.46551f, 0.46733f, 0.46914f, 0.47095f, + 0.47275f, 0.47454f, 0.47633f, 0.47811f, + 0.47989f, 0.48166f, 0.48342f, 0.48518f, + 0.48693f, 0.48867f, 0.49041f, 0.49214f, + 0.49387f, 0.49559f, 0.49730f, 0.49901f, + 0.50072f, 0.50241f, 0.50410f, 0.50579f, + 0.50747f, 0.50914f, 0.51081f, 0.51247f, + 0.51413f, 0.51578f, 0.51742f, 0.51906f, + 0.52069f, 0.52232f, 0.52394f, 0.52556f, + 0.52717f, 0.52878f, 0.53038f, 0.53197f, + 0.53356f, 0.53514f, 0.53672f, 0.53829f, + 0.53986f, 0.54142f, 0.54297f, 0.54452f, + 0.54607f, 0.54761f, 0.54914f, 0.55067f, + 0.55220f, 0.55371f, 0.55523f, 0.55673f, + 0.55824f, 0.55973f, 0.56123f, 0.56271f, + 0.56420f, 0.56567f, 0.56715f, 0.56861f, + 0.57007f, 0.57153f, 0.57298f, 0.57443f, + 0.57587f, 0.57731f, 0.57874f, 0.58017f, + 0.58159f, 0.58301f, 0.58443f, 0.58583f, + 0.58724f, 0.58864f, 0.59003f, 0.59142f, + 0.59281f, 0.59419f, 0.59556f, 0.59694f, + 0.59830f, 0.59966f, 0.60102f, 0.60238f, + 0.60373f, 0.60507f, 0.60641f, 0.60775f, + 0.60908f, 0.61040f, 0.61173f, 0.61305f, + 0.61436f, 0.61567f, 0.61698f, 0.61828f, + 0.61957f, 0.62087f, 0.62216f, 0.62344f, + 0.62472f, 0.62600f, 0.62727f, 0.62854f, + 0.62980f, 0.63106f, 0.63232f, 0.63357f, + 0.63482f, 0.63606f, 0.63730f, 0.63854f, + 0.63977f, 0.64100f, 0.64222f, 0.64344f, + 0.64466f, 0.64587f, 0.64708f, 0.64829f, + 0.64949f, 0.65069f, 0.65188f, 0.65307f, + 0.65426f, 0.65544f, 0.65662f, 0.65779f, + 0.65897f, 0.66013f, 0.66130f, 0.66246f, + 0.66362f, 0.66477f, 0.66592f, 0.66707f, + 0.66821f, 0.66935f, 0.67048f, 0.67162f, + 0.67275f, 0.67387f, 0.67499f, 0.67611f, + 0.67723f, 0.67834f, 0.67945f, 0.68055f, + 0.68165f, 0.68275f, 0.68385f, 0.68494f, + 0.68603f, 0.68711f, 0.68819f, 0.68927f, + 0.69035f, 0.69142f, 0.69249f, 0.69355f, + 0.69461f, 0.69567f, 0.69673f, 0.69778f, + 0.69883f, 0.69988f, 0.70092f, 0.70196f, + 0.70300f, 0.70403f, 0.70506f, 0.70609f, + 0.70711f, 0.70813f, 0.70915f, 0.71017f, + 0.71118f, 0.71219f, 0.71319f, 0.71420f, + 0.71520f, 0.71620f, 0.71719f, 0.71818f, + 0.71917f, 0.72016f, 0.72114f, 0.72212f, + 0.72309f, 0.72407f, 0.72504f, 0.72601f, + 0.72697f, 0.72794f, 0.72890f, 0.72985f, + 0.73081f, 0.73176f, 0.73271f, 0.73365f, + 0.73460f, 0.73554f, 0.73647f, 0.73741f, + 0.73834f, 0.73927f, 0.74020f, 0.74112f, + 0.74204f, 0.74296f, 0.74388f, 0.74479f, + 0.74570f, 0.74661f, 0.74751f, 0.74842f, + 0.74932f, 0.75021f, 0.75111f, 0.75200f, + 0.75289f, 0.75378f, 0.75466f, 0.75555f, + 0.75643f, 0.75730f, 0.75818f, 0.75905f, + 0.75992f, 0.76079f, 0.76165f, 0.76251f, + 0.76337f, 0.76423f, 0.76508f, 0.76594f, + 0.76679f, 0.76763f, 0.76848f, 0.76932f, + 0.77016f, 0.77100f, 0.77183f, 0.77267f, + 0.77350f, 0.77432f, 0.77515f, 0.77597f, + 0.77680f, 0.77761f, 0.77843f, 0.77924f, + 0.78006f, 0.78087f, 0.78167f, 0.78248f, + 0.78328f, 0.78408f, 0.78488f, 0.78568f, + 0.78647f, 0.78726f, 0.78805f, 0.78884f, + 0.78962f, 0.79040f, 0.79118f, 0.79196f, + 0.79274f, 0.79351f, 0.79428f, 0.79505f, + 0.79582f, 0.79658f, 0.79735f, 0.79811f, + 0.79887f, 0.79962f, 0.80038f, 0.80113f, + 0.80188f, 0.80263f, 0.80337f, 0.80412f, + 0.80486f, 0.80560f, 0.80634f, 0.80707f, + 0.80780f, 0.80854f, 0.80926f, 0.80999f, + 0.81072f, 0.81144f, 0.81216f, 0.81288f, + 0.81360f, 0.81431f, 0.81503f, 0.81574f, + 0.81645f, 0.81715f, 0.81786f, 0.81856f, + 0.81926f, 0.81996f, 0.82066f, 0.82135f, + 0.82205f, 0.82274f, 0.82343f, 0.82412f, + 0.82480f, 0.82549f, 0.82617f, 0.82685f, + 0.82753f, 0.82820f, 0.82888f, 0.82955f, + 0.83022f, 0.83089f, 0.83155f, 0.83222f, + 0.83288f, 0.83354f, 0.83420f, 0.83486f, + 0.83552f, 0.83617f, 0.83682f, 0.83747f, + 0.83812f, 0.83877f, 0.83941f, 0.84005f, + 0.84069f, 0.84133f, 0.84197f, 0.84261f, + 0.84324f, 0.84387f, 0.84450f, 0.84513f, + 0.84576f, 0.84639f, 0.84701f, 0.84763f, + 0.84825f, 0.84887f, 0.84949f, 0.85010f, + 0.85071f, 0.85132f, 0.85193f, 0.85254f, + 0.85315f, 0.85375f, 0.85436f, 0.85496f, + 0.85556f, 0.85615f, 0.85675f, 0.85735f, + 0.85794f, 0.85853f, 0.85912f, 0.85971f, + 0.86029f, 0.86088f, 0.86146f, 0.86204f, + 0.86262f, 0.86320f, 0.86378f, 0.86435f, + 0.86493f, 0.86550f, 0.86607f, 0.86664f, + 0.86720f, 0.86777f, 0.86833f, 0.86889f, + 0.86945f, 0.87001f, 0.87057f, 0.87113f, + 0.87168f, 0.87223f, 0.87278f, 0.87333f, + 0.87388f, 0.87443f, 0.87497f, 0.87552f, + 0.87606f, 0.87660f, 0.87714f, 0.87768f, + 0.87821f, 0.87875f, 0.87928f, 0.87981f, + 0.88034f, 0.88087f, 0.88140f, 0.88192f, + 0.88244f, 0.88297f, 0.88349f, 0.88401f, + 0.88453f, 0.88504f, 0.88556f, 0.88607f, + 0.88658f, 0.88709f, 0.88760f, 0.88811f, + 0.88862f, 0.88912f, 0.88963f, 0.89013f, + 0.89063f, 0.89113f, 0.89163f, 0.89212f, + 0.89262f, 0.89311f, 0.89360f, 0.89409f, + 0.89458f, 0.89507f, 0.89556f, 0.89604f, + 0.89653f, 0.89701f, 0.89749f, 0.89797f, + 0.89845f, 0.89892f, 0.89940f, 0.89987f, + 0.90035f, 0.90082f, 0.90129f, 0.90176f, + 0.90222f, 0.90269f, 0.90316f, 0.90362f, + 0.90408f, 0.90454f, 0.90500f, 0.90546f, + 0.90592f, 0.90637f, 0.90683f, 0.90728f, + 0.90773f, 0.90818f, 0.90863f, 0.90908f, + 0.90952f, 0.90997f, 0.91041f, 0.91085f, + 0.91130f, 0.91173f, 0.91217f, 0.91261f, + 0.91305f, 0.91348f, 0.91392f, 0.91435f, + 0.91478f, 0.91521f, 0.91564f, 0.91606f, + 0.91649f, 0.91691f, 0.91734f, 0.91776f, + 0.91818f, 0.91860f, 0.91902f, 0.91944f, + 0.91985f, 0.92027f, 0.92068f, 0.92109f, + 0.92150f, 0.92191f, 0.92232f, 0.92273f, + 0.92314f, 0.92354f, 0.92395f, 0.92435f, + 0.92475f, 0.92515f, 0.92555f, 0.92595f, + 0.92634f, 0.92674f, 0.92713f, 0.92753f, + 0.92792f, 0.92831f, 0.92870f, 0.92909f, + 0.92947f, 0.92986f, 0.93025f, 0.93063f, + 0.93101f, 0.93139f, 0.93177f, 0.93215f, + 0.93253f, 0.93291f, 0.93328f, 0.93366f, + 0.93403f, 0.93440f, 0.93478f, 0.93515f, + 0.93551f, 0.93588f, 0.93625f, 0.93661f, + 0.93698f, 0.93734f, 0.93770f, 0.93807f, + 0.93843f, 0.93878f, 0.93914f, 0.93950f, + 0.93986f, 0.94021f, 0.94056f, 0.94092f, + 0.94127f, 0.94162f, 0.94197f, 0.94231f, + 0.94266f, 0.94301f, 0.94335f, 0.94369f, + 0.94404f, 0.94438f, 0.94472f, 0.94506f, + 0.94540f, 0.94573f, 0.94607f, 0.94641f, + 0.94674f, 0.94707f, 0.94740f, 0.94774f, + 0.94807f, 0.94839f, 0.94872f, 0.94905f, + 0.94937f, 0.94970f, 0.95002f, 0.95035f, + 0.95067f, 0.95099f, 0.95131f, 0.95163f, + 0.95194f, 0.95226f, 0.95257f, 0.95289f, + 0.95320f, 0.95351f, 0.95383f, 0.95414f, + 0.95445f, 0.95475f, 0.95506f, 0.95537f, + 0.95567f, 0.95598f, 0.95628f, 0.95658f, + 0.95688f, 0.95718f, 0.95748f, 0.95778f, + 0.95808f, 0.95838f, 0.95867f, 0.95897f, + 0.95926f, 0.95955f, 0.95984f, 0.96013f, + 0.96042f, 0.96071f, 0.96100f, 0.96129f, + 0.96157f, 0.96186f, 0.96214f, 0.96242f, + 0.96271f, 0.96299f, 0.96327f, 0.96355f, + 0.96382f, 0.96410f, 0.96438f, 0.96465f, + 0.96493f, 0.96520f, 0.96547f, 0.96574f, + 0.96602f, 0.96629f, 0.96655f, 0.96682f, + 0.96709f, 0.96735f, 0.96762f, 0.96788f, + 0.96815f, 0.96841f, 0.96867f, 0.96893f, + 0.96919f, 0.96945f, 0.96971f, 0.96996f, + 0.97022f, 0.97047f, 0.97073f, 0.97098f, + 0.97123f, 0.97149f, 0.97174f, 0.97199f, + 0.97223f, 0.97248f, 0.97273f, 0.97297f, + 0.97322f, 0.97346f, 0.97371f, 0.97395f, + 0.97419f, 0.97443f, 0.97467f, 0.97491f, + 0.97515f, 0.97539f, 0.97562f, 0.97586f, + 0.97609f, 0.97633f, 0.97656f, 0.97679f, + 0.97702f, 0.97725f, 0.97748f, 0.97771f, + 0.97794f, 0.97817f, 0.97839f, 0.97862f, + 0.97884f, 0.97907f, 0.97929f, 0.97951f, + 0.97973f, 0.97995f, 0.98017f, 0.98039f, + 0.98061f, 0.98082f, 0.98104f, 0.98125f, + 0.98147f, 0.98168f, 0.98189f, 0.98211f, + 0.98232f, 0.98253f, 0.98274f, 0.98295f, + 0.98315f, 0.98336f, 0.98357f, 0.98377f, + 0.98398f, 0.98418f, 0.98438f, 0.98458f, + 0.98478f, 0.98498f, 0.98518f, 0.98538f, + 0.98558f, 0.98578f, 0.98597f, 0.98617f, + 0.98636f, 0.98656f, 0.98675f, 0.98694f, + 0.98714f, 0.98733f, 0.98752f, 0.98771f, + 0.98789f, 0.98808f, 0.98827f, 0.98845f, + 0.98864f, 0.98882f, 0.98901f, 0.98919f, + 0.98937f, 0.98955f, 0.98973f, 0.98991f, + 0.99009f, 0.99027f, 0.99045f, 0.99063f, + 0.99080f, 0.99098f, 0.99115f, 0.99133f, + 0.99150f, 0.99167f, 0.99184f, 0.99201f, + 0.99218f, 0.99235f, 0.99252f, 0.99269f, + 0.99285f, 0.99302f, 0.99319f, 0.99335f, + 0.99351f, 0.99368f, 0.99384f, 0.99400f, + 0.99416f, 0.99432f, 0.99448f, 0.99464f, + 0.99480f, 0.99495f, 0.99511f, 0.99527f, + 0.99542f, 0.99558f, 0.99573f, 0.99588f, + 0.99603f, 0.99619f, 0.99634f, 0.99649f, + 0.99664f, 0.99678f, 0.99693f, 0.99708f, + 0.99722f, 0.99737f, 0.99751f, 0.99766f, + 0.99780f, 0.99794f, 0.99809f, 0.99823f, + 0.99837f, 0.99851f, 0.99865f, 0.99879f, + 0.99892f, 0.99906f, 0.99920f, 0.99933f, + 0.99947f, 0.99960f, 0.99974f, 0.99987f, + 1.00000f +}; + +// This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here +static float sRGBGammaForward (const float x) { + if (x <= 0.0031308) + return x * 12.92; + else if (x > 1.0) + return 1.0 + (x - 1.0) * (1.055*(1.0/2.4)); // linear extension + else + return 1.055 * pow (x, 1.0 / 2.4) - 0.055; +} +static float sRGBGammaInverse (const float y) { + if (y <= 0.0031308 * 12.92) + return y * (1.0 / 12.92); + else if (y > 1.0) + return 1.0 + (y - 1.0) / (1.055*(1.0/2.4)); + else + return pow ((y + 0.055) * (1.0 / 1.055), 2.4); +} + +static void Invert3x3(const double (*A)[3], double (*B)[3]) { + + double a00 = A[0][0]; + double a01 = A[0][1]; + double a02 = A[0][2]; + double a10 = A[1][0]; + double a11 = A[1][1]; + double a12 = A[1][2]; + double a20 = A[2][0]; + double a21 = A[2][1]; + double a22 = A[2][2]; + double temp [3][3]; + + temp[0][0] = a11 * a22 - a21 * a12; + temp[0][1] = a21 * a02 - a01 * a22; + temp[0][2] = a01 * a12 - a11 * a02; + temp[1][0] = a20 * a12 - a10 * a22; + temp[1][1] = a00 * a22 - a20 * a02; + temp[1][2] = a10 * a02 - a00 * a12; + temp[2][0] = a10 * a21 - a20 * a11; + temp[2][1] = a20 * a01 - a00 * a21; + temp[2][2] = a00 * a11 - a10 * a01; + + double det = a00 * temp[0][0] + a01 * temp[1][0] + a02 * temp[2][0]; + + if (fabs(det) < 1.0E-10) { + abort(); // can't be inverted, we shouldn't be dealing with such matrices + } + + for (int j = 0; j < 3; j++) { + for (int k = 0; k < 3; k++) { + B[j][k] = temp[j][k] / det; + } + } +} + +static void Multiply3x3(const double (*A)[3], const double (*B)[3], double (*C)[3]) { + + // use temp to support having output same as input + double M[3][3]; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + M[i][j] = 0; + for (int k = 0; k < 3; k++) { + M[i][j] += A[i][k] * B[k][j]; + } + } + } + memcpy(C, M, 3 * 3 * sizeof(double)); +} + +static void Multiply3x3_v3(const double (*A)[3], const double B[3], double C[3]) { + + // use temp to support having output same as input + double M[3] = { 0, 0, 0 }; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + M[i] += A[i][j] * B[j]; + } + } + memcpy(C, M, 3 * sizeof(double)); +} + +static void Mix3x3(const double (*A)[3], double mulA, const double (*B)[3], double mulB, double (*C)[3]) { + + double M[3][3]; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + M[i][j] = A[i][j] * mulA + B[i][j] * mulB; + } + } + memcpy(C, M, 3 * 3 * sizeof(double)); +} + +static void MapWhiteMatrix(const double white1[3], const double white2[3], double (*B)[3]) { + + // code adapted from dng_color_spec::MapWhiteMatrix + + // Use the linearized Bradford adaptation matrix. + double Mb[3][3] = { { 0.8951, 0.2664, -0.1614 }, { -0.7502, 1.7135, 0.0367 }, { 0.0389, -0.0685, 1.0296 }}; + + double w1[3]; + Multiply3x3_v3(Mb, white1, w1); + double w2[3]; + Multiply3x3_v3(Mb, white2, w2); + + // Negative white coordinates are kind of meaningless. + w1[0] = std::max(w1[0], 0.0); + w1[1] = std::max(w1[1], 0.0); + w1[2] = std::max(w1[2], 0.0); + w2[0] = std::max(w2[0], 0.0); + w2[1] = std::max(w2[1], 0.0); + w2[2] = std::max(w2[2], 0.0); + + // Limit scaling to something reasonable. + double A[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + A[0][0] = std::max(0.1, std::min(w1[0] > 0.0 ? w2[0] / w1[0] : 10.0, 10.0)); + A[1][1] = std::max(0.1, std::min(w1[1] > 0.0 ? w2[1] / w1[1] : 10.0, 10.0)); + A[2][2] = std::max(0.1, std::min(w1[2] > 0.0 ? w2[2] / w1[2] : 10.0, 10.0)); + + double temp[3][3]; + Invert3x3(Mb, temp); + Multiply3x3(temp, A, temp); + Multiply3x3(temp, Mb, B); +} + +static void XYZtoXY(const double XYZ[3], double XY[2]) { + double X = XYZ[0]; + double Y = XYZ[1]; + double Z = XYZ[2]; + double total = X + Y + Z; + if (total > 0.0) { + XY[0] = X / total; + XY[1] = Y / total; + } else { + XY[0] = 0.3457; + XY[1] = 0.3585; + } +} + +static void XYtoXYZ(const double XY[2], double XYZ[3]) { + double temp[2] = { XY[0], XY[1] }; + // Restrict xy coord to someplace inside the range of real xy coordinates. + // This prevents math from doing strange things when users specify + // extreme temperature/tint coordinates. + temp[0] = std::max(0.000001, std::min(temp[0], 0.999999)); + temp[1] = std::max(0.000001, std::min(temp[1], 0.999999)); + if (temp[0] + temp[1] > 0.999999) { + double scale = 0.999999 / (temp[0] + temp[1]); + temp[0] *= scale; + temp[1] *= scale; + } + XYZ[0] = temp[0] / temp[1]; + XYZ[1] = 1.0; + XYZ[2] = (1.0 - temp[0] - temp[1]) / temp[1]; +} + +enum dngCalibrationIlluminant { + lsUnknown = 0, + lsDaylight = 1, + lsFluorescent = 2, + lsTungsten = 3, + lsFlash = 4, + lsFineWeather = 9, + lsCloudyWeather = 10, + lsShade = 11, + lsDaylightFluorescent = 12, // D 5700 - 7100K + lsDayWhiteFluorescent = 13, // N 4600 - 5500K + lsCoolWhiteFluorescent = 14, // W 3800 - 4500K + lsWhiteFluorescent = 15, // WW 3250 - 3800K + lsWarmWhiteFluorescent = 16, // L 2600 - 3250K + lsStandardLightA = 17, + lsStandardLightB = 18, + lsStandardLightC = 19, + lsD55 = 20, + lsD65 = 21, + lsD75 = 22, + lsD50 = 23, + lsISOStudioTungsten = 24, + lsOther = 255 +}; + +// should probably be moved to colortemp.cc +static double calibrationIlluminantToTemperature(int light) { + + // these temperatures are those found in DNG SDK reference code. + switch (light) { + case lsStandardLightA: + case lsTungsten: + return 2850.0; + case lsISOStudioTungsten: + return 3200.0; + case lsD50: + return 5000.0; + case lsD55: + case lsDaylight: + case lsFineWeather: + case lsFlash: + case lsStandardLightB: + return 5500.0; + case lsD65: + case lsStandardLightC: + case lsCloudyWeather: + return 6500.0; + case lsD75: + case lsShade: + return 7500.0; + case lsDaylightFluorescent: + return (5700.0 + 7100.0) * 0.5; + case lsDayWhiteFluorescent: + return (4600.0 + 5500.0) * 0.5; + case lsCoolWhiteFluorescent: + case lsFluorescent: + return (3800.0 + 4500.0) * 0.5; + case lsWhiteFluorescent: + return (3250.0 + 3800.0) * 0.5; + case lsWarmWhiteFluorescent: + return (2600.0 + 3250.0) * 0.5; + default: + return 0.0; + } +} +void DCPProfile::MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const +{ + // code adapted from dng_color_spec::FindXYZtoCamera + // note that we do not support monochrome or colorplanes > 3 (no reductionMatrix support) + // we do not support cameracalibration either + + double neutral[3]; // same as the DNG "AsShotNeutral" tag if white balance is Camera's own + { + /* A bit messy matrixing and conversions to get the neutral[] array from RT's own white balance which is stored in + sRGB space, while the DCP code needs multipliers in CameraRGB space */ + double r, g, b; + wb.getMultipliers(r, g, b); + + // camWbMatrix == imatrices.xyz_cam + double cam_xyz[3][3]; + Invert3x3(camWbMatrix, cam_xyz); + double cam_rgb[3][3]; + Multiply3x3(cam_xyz, xyz_sRGB, cam_rgb); + double camwb_red = cam_rgb[0][0]*r + cam_rgb[0][1]*g + cam_rgb[0][2]*b; + double camwb_green = cam_rgb[1][0]*r + cam_rgb[1][1]*g + cam_rgb[1][2]*b; + double camwb_blue = cam_rgb[2][0]*r + cam_rgb[2][1]*g + cam_rgb[2][2]*b; + neutral[0] = camwb_red / pre_mul[0]; + neutral[1] = camwb_green / pre_mul[1]; + neutral[2] = camwb_blue / pre_mul[2]; + double maxentry = 0; + for (int i = 0; i < 3; i++) { + if (neutral[i] > maxentry) { + maxentry = neutral[i]; + } + } + for (int i = 0; i < 3; i++) { + neutral[i] /= maxentry; + } + } + + /* Calculate what the RGB multipliers corresponds to as a white XY coordinate, based on the + DCP ColorMatrix or ColorMatrices if dual-illuminant. This is the DNG reference code way to + do it, which is a bit different from RT's own white balance model at the time of writing. + When RT's white balance can make use of the DCP color matrices we could use that instead. */ + double white_xy[2]; + dngref_NeutralToXY(neutral, preferredIlluminant, white_xy); + + bool hasFwd1 = hasForwardMatrix1; + bool hasFwd2 = hasForwardMatrix2; + bool hasCol1 = hasColorMatrix1; + bool hasCol2 = hasColorMatrix2; + if (preferredIlluminant == 1) { + if (hasFwd1) hasFwd2 = false; + if (hasCol1) hasCol2 = false; + } else if (preferredIlluminant == 2) { + if (hasFwd2) hasFwd1 = false; + if (hasCol2) hasCol1 = false; + } + + // mix if we have two matrices + double mix = 1.0; + if ((hasCol1 && hasCol2) || (hasFwd1 && hasFwd2)) { + double wbtemp; + /* DNG ref way to convert XY to temperature, which affect matrix mixing. A different model here + typically does not affect the result too much, ie it's probably not strictly necessary to + use the DNG reference code here, but we do it for now. */ + dngref_XYCoord2Temperature(white_xy, &wbtemp, NULL); + if (wbtemp <= temperature1) { + mix = 1.0; + } else if (wbtemp >= temperature2) { + mix = 0.0; + } else { + double invT = 1.0 / wbtemp; + mix = (invT - (1.0 / temperature2)) / ((1.0 / temperature1) - (1.0 / temperature2)); + } + } + + // Colormatrix + double mCol[3][3]; + if (hasCol1 && hasCol2) { + // interpolate + if (mix >= 1.0) { + memcpy(mCol, mColorMatrix1, sizeof(mCol)); + } else if (mix <= 0.0) { + memcpy(mCol, mColorMatrix2, sizeof(mCol)); + } else { + Mix3x3(mColorMatrix1, mix, mColorMatrix2, 1.0 - mix, mCol); + } + } else if (hasCol1) { + memcpy(mCol, mColorMatrix1, sizeof(mCol)); + } else { + memcpy(mCol, mColorMatrix2, sizeof(mCol)); + } + + /* + The exact position of the white XY coordinate affects the result very much, thus + it's important that the result is very similar or the same as DNG reference code. + Especially important is it that the raw-embedded "AsShot" multipliers is translated + to the same white XY coordinate as the DNG reference code, or else third party DCPs + will show incorrect color. + */ + + double white_xyz[3]; + XYtoXYZ(white_xy, white_xyz); + + double cam_xyz[3][3]; + if (hasFwd1 || hasFwd2) { + // always prefer ForwardMatrix ahead of ColorMatrix + double mFwd[3][3]; + if (hasFwd1 && hasFwd2) { + // interpolate + if (mix >= 1.0) { + memcpy(mFwd, mForwardMatrix1, sizeof(mFwd)); + } else if (mix <= 0.0) { + memcpy(mFwd, mForwardMatrix2, sizeof(mFwd)); + } else { + Mix3x3(mForwardMatrix1, mix, mForwardMatrix2, 1.0 - mix, mFwd); + } + } else if (hasFwd1) { + memcpy(mFwd, mForwardMatrix1, sizeof(mFwd)); + } else { + memcpy(mFwd, mForwardMatrix2, sizeof(mFwd)); + } + // adapted from dng_color_spec::SetWhiteXY + double CameraWhite[3]; + Multiply3x3_v3(mCol, white_xyz, CameraWhite); + + double whiteDiag[3][3] = {{CameraWhite[0], 0, 0}, {0, CameraWhite[1], 0}, {0, 0, CameraWhite[2]}}; + double whiteDiagInv[3][3]; + Invert3x3(whiteDiag, whiteDiagInv); + + double xyz_cam[3][3]; + Multiply3x3(mFwd, whiteDiagInv, xyz_cam); + Invert3x3(xyz_cam, cam_xyz); + } else { + double whiteMatrix[3][3]; + const double white_d50[3] = { 0.3457, 0.3585, 0.2958 }; // D50 + MapWhiteMatrix(white_d50, white_xyz, whiteMatrix); + Multiply3x3(mCol, whiteMatrix, cam_xyz); + } + + // convert cam_xyz (XYZ D50 to CameraRGB, "PCS to Camera" in DNG terminology) to mXYZCAM + + { + // This block can probably be simplified, seems unnecessary to pass through the sRGB matrix + // (probably dcraw legacy), it does no harm though as we don't clip anything. + int i,j,k; + + // Multiply out XYZ colorspace + double cam_rgb[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + for (k=0; k < 3; k++) + cam_rgb[i][j] += cam_xyz[i][k] * xyz_sRGB[k][j]; + + // Normalize cam_rgb so that: cam_rgb * (1,1,1) is (1,1,1,1) + double num; + for (i=0; i<3; i++) { + for (num=j=0; j<3; j++) num += cam_rgb[i][j]; + for (j=0; j<3; j++) cam_rgb[i][j] /= num; + } + + double rgb_cam[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + RawImageSource::inverse33 (cam_rgb, rgb_cam); + + for (i=0; i<3; i++) + for (j=0; j<3; j++) mXYZCAM[i][j]=0; + for (i=0; i<3; i++) + for (j=0; j<3; j++) + for (k=0; k<3; k++) + mXYZCAM[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; + } +} + +const DCPProfile::HSBModify* DCPProfile::MakeHueSatMap(ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const { + + *deleteHandle = NULL; + if (!aDeltas1) { + return NULL; + } + if (!aDeltas2) { + return aDeltas1; + } + + if (preferredIlluminant == 1) { + return aDeltas1; + } else if (preferredIlluminant == 2) { + return aDeltas2; + } + + // Interpolate based on color temperature. + if (temperature1 <= 0.0 || temperature2 <= 0.0 || temperature1 == temperature2) { + return aDeltas1; + } + bool reverseOrder = temperature1 > temperature2; + double t1, t2; + if (reverseOrder) { + t1 = temperature2; + t2 = temperature1; + } else { + t1 = temperature1; + t2 = temperature2; + } + + double mix; + if (wb.getTemp() <= t1) { + mix = 1.0; + } else if (wb.getTemp() >= t2) { + mix = 0.0; + } else { + double invT = 1.0 / wb.getTemp(); + mix = (invT - (1.0 / t2)) / ((1.0 / t1) - (1.0 / t2)); + } + + if (reverseOrder) { + mix = 1.0 - mix; + } + + if (mix >= 1.0) { + return aDeltas1; + } else if (mix <= 0.0) { + return aDeltas2; + } + + // Interpolate between the tables. + HSBModify *aDeltas = new HSBModify[DeltaInfo.iArrayCount]; + *deleteHandle = aDeltas; + float w1 = (float)mix; + float w2 = 1.0f - (float)mix; + for (int i = 0; i < DeltaInfo.iArrayCount; i++) { + aDeltas[i].fHueShift = w1 * aDeltas1[i].fHueShift + w2 * aDeltas2[i].fHueShift; + aDeltas[i].fSatScale = w1 * aDeltas1[i].fSatScale + w2 * aDeltas2[i].fSatScale; + aDeltas[i].fValScale = w1 * aDeltas1[i].fValScale + w2 * aDeltas2[i].fValScale; + } + return aDeltas; +} + +DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { + const int TIFFFloatSize=4; + const int TagColorMatrix1=50721, TagColorMatrix2=50722, TagProfileHueSatMapDims=50937; + const int TagForwardMatrix1=50964, TagForwardMatrix2=50965; + const int TagProfileHueSatMapData1=50938, TagProfileHueSatMapData2=50939; + const int TagCalibrationIlluminant1=50778, TagCalibrationIlluminant2=50779; + const int TagProfileLookTableData=50982, TagProfileLookTableDims=50981; // ProfileLookup is the low quality variant + const int TagProfileHueSatMapEncoding=51107, TagProfileLookTableEncoding=51108; + const int TagProfileToneCurve=50940, TagBaselineExposureOffset=51109; + const int TagProfileCopyright=50942; + + aDeltas1=aDeltas2=aLookTable=NULL; + + FILE *pFile = safe_g_fopen(fname, "rb"); + + TagDirectory *tagDir=ExifManager::parseTIFF(pFile, false); + + Tag* tag = tagDir->getTag(TagCalibrationIlluminant1); iLightSource1 = (tag!=NULL ? tag->toInt(0,rtexif::SHORT) : -1); + tag = tagDir->getTag(TagCalibrationIlluminant2); iLightSource2 = (tag!=NULL ? tag->toInt(0,rtexif::SHORT) : -1); + temperature1 = calibrationIlluminantToTemperature(iLightSource1); + temperature2 = calibrationIlluminantToTemperature(iLightSource2); + + bool hasSecondHueSat = tagDir->getTag(TagProfileHueSatMapData2)!=NULL; // some profiles have two matrices, but just one huesat + + // Fetch Forward Matrices, if any + hasForwardMatrix1 = false; + hasForwardMatrix2 = false; + hasColorMatrix1 = false; + hasColorMatrix2 = false; + hasToneCurve = false; + hasBaselineExposureOffset = false; + baselineExposureOffset = 0; + tag = tagDir->getTag(TagForwardMatrix1); + if (tag) { + hasForwardMatrix1 = true; + for (int row=0;row<3;row++) { + for (int col=0;col<3;col++) { + mForwardMatrix1[row][col]=(float)tag->toDouble((col+row*3)*8); + } + } + } + tag = tagDir->getTag(TagForwardMatrix2); + if (tag) { + hasForwardMatrix2 = true; + for (int row=0;row<3;row++) { + for (int col=0;col<3;col++) { + mForwardMatrix2[row][col]=(float)tag->toDouble((col+row*3)*8); + } + } + } + + // Color Matrix (1 is always there) + tag = tagDir->getTag(TagColorMatrix1); + if (!tag) { + // FIXME: better error handling + fprintf(stderr, "Bad DCP, no ColorMatrix1\n"); + abort(); + } + hasColorMatrix1 = true; + + for (int row=0;row<3;row++) { + for (int col=0;col<3;col++) { + mColorMatrix1[row][col]=(float)tag->toDouble((col+row*3)*8); + } + } + + tag=tagDir->getTag(TagProfileLookTableDims); + if (tag!=NULL) { + LookInfo.iHueDivisions=tag->toInt(0); LookInfo.iSatDivisions=tag->toInt(4); LookInfo.iValDivisions=tag->toInt(8); + + tag = tagDir->getTag(TagProfileLookTableEncoding); + LookInfo.sRGBGamma = tag != NULL && tag->toInt(0); + + tag = tagDir->getTag(TagProfileLookTableData); + LookInfo.iArrayCount = tag->getCount()/3; + + aLookTable =new HSBModify[LookInfo.iArrayCount]; + + for (int i=0;itoDouble((i*3)*TIFFFloatSize); + aLookTable[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize); + aLookTable[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize); + } + + // precalculated constants for table application + LookInfo.pc.hScale = (LookInfo.iHueDivisions < 2) ? 0.0f : (LookInfo.iHueDivisions * (1.0f / 6.0f)); + LookInfo.pc.sScale = (float) (LookInfo.iSatDivisions - 1); + LookInfo.pc.vScale = (float) (LookInfo.iValDivisions - 1); + LookInfo.pc.maxHueIndex0 = LookInfo.iHueDivisions - 1; + LookInfo.pc.maxSatIndex0 = LookInfo.iSatDivisions - 2; + LookInfo.pc.maxValIndex0 = LookInfo.iValDivisions - 2; + LookInfo.pc.hueStep = LookInfo.iSatDivisions; + LookInfo.pc.valStep = LookInfo.iHueDivisions * LookInfo.pc.hueStep; + } + + tag = tagDir->getTag(TagProfileHueSatMapDims); + if (tag!=NULL) { + DeltaInfo.iHueDivisions=tag->toInt(0); DeltaInfo.iSatDivisions=tag->toInt(4); DeltaInfo.iValDivisions=tag->toInt(8); + + tag = tagDir->getTag(TagProfileHueSatMapEncoding); + DeltaInfo.sRGBGamma = tag != NULL && tag->toInt(0); + + tag = tagDir->getTag(TagProfileHueSatMapData1); + DeltaInfo.iArrayCount = tag->getCount()/3; + + aDeltas1=new HSBModify[DeltaInfo.iArrayCount]; + + for (int i=0;itoDouble((i*3)*TIFFFloatSize); + aDeltas1[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize); + aDeltas1[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize); + } + + DeltaInfo.pc.hScale = (DeltaInfo.iHueDivisions < 2) ? 0.0f : (DeltaInfo.iHueDivisions * (1.0f / 6.0f)); + DeltaInfo.pc.sScale = (float) (DeltaInfo.iSatDivisions - 1); + DeltaInfo.pc.vScale = (float) (DeltaInfo.iValDivisions - 1); + DeltaInfo.pc.maxHueIndex0 = DeltaInfo.iHueDivisions - 1; + DeltaInfo.pc.maxSatIndex0 = DeltaInfo.iSatDivisions - 2; + DeltaInfo.pc.maxValIndex0 = DeltaInfo.iValDivisions - 2; + DeltaInfo.pc.hueStep = DeltaInfo.iSatDivisions; + DeltaInfo.pc.valStep = DeltaInfo.iHueDivisions * DeltaInfo.pc.hueStep; + } + + if (iLightSource2!=-1) { + // Second matrix + tag = tagDir->getTag(TagColorMatrix2); + hasColorMatrix2 = true; + + for (int row=0;row<3;row++) { + for (int col=0;col<3;col++) { + mColorMatrix2[row][col]= (tag!=NULL ? (float)tag->toDouble((col+row*3)*8) : mColorMatrix1[row][col]); + } + } + + // Second huesatmap + if (hasSecondHueSat) { + aDeltas2=new HSBModify[DeltaInfo.iArrayCount]; + + // Saturation maps. Need to be unwinded. + tag = tagDir->getTag(TagProfileHueSatMapData2); + + for (int i=0;itoDouble((i*3)*TIFFFloatSize); + aDeltas2[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize); + aDeltas2[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize); + } + } + } + + tag = tagDir->getTag(TagBaselineExposureOffset); + if (tag) { + hasBaselineExposureOffset = true; + baselineExposureOffset = tag->toDouble(); + } + + // Read tone curve points, if any, but disable to RTs own profiles + tag = tagDir->getTag(TagProfileToneCurve); + if (tag!=NULL && !isRTProfile) { + std::vector cPoints; + cPoints.push_back(double(DCT_Spline)); // The first value is the curve type + + // push back each X/Y coordinates in a loop + bool curve_is_linear = true; + for (int i=0;igetCount(); i+= 2) { + double x = tag->toDouble((i+0)*TIFFFloatSize); + double y = tag->toDouble((i+1)*TIFFFloatSize); + if (x != y) { + curve_is_linear = false; + } + cPoints.push_back( x ); + cPoints.push_back( y ); + } + + if (!curve_is_linear) { + // Create the curve + DiagonalCurve rawCurve(cPoints, CURVES_MIN_POLY_POINTS); + + toneCurve.Set((Curve*)&rawCurve); + hasToneCurve = true; + } + } else if (tag == NULL) { + tag = tagDir->getTag(TagProfileCopyright); + if (tag!=NULL && tag->valueToString().find("Adobe Systems") != std::string::npos) { + // an Adobe profile without tone curve is expected to have the Adobe Default Curve, we add that + std::vector cPoints; + cPoints.push_back(double(DCT_Spline)); + const size_t tc_len = sizeof(adobe_camera_raw_default_curve)/sizeof(adobe_camera_raw_default_curve[0]); + for (size_t i = 0; i < tc_len; i++) { + double x = (double)i / (tc_len - 1); + double y = (double)adobe_camera_raw_default_curve[i]; + cPoints.push_back( x ); + cPoints.push_back( y ); + } + DiagonalCurve rawCurve(cPoints, CURVES_MIN_POLY_POINTS); + toneCurve.Set((Curve*)&rawCurve); + hasToneCurve = true; + } + } + + willInterpolate = false; + if (hasForwardMatrix1) { + if (hasForwardMatrix2) { + if (memcmp(mForwardMatrix1, mForwardMatrix2, sizeof(mForwardMatrix1)) != 0) { + // common that forward matrices are the same! + willInterpolate = true; + } + if (aDeltas1 && aDeltas2) { + // we assume tables are different + willInterpolate = true; + } + } + } + if (hasColorMatrix1 && hasColorMatrix2) { + if (memcmp(mColorMatrix1, mColorMatrix2, sizeof(mColorMatrix1)) != 0) { + willInterpolate = true; + } + if (aDeltas1 && aDeltas2) { + willInterpolate = true; + } + } + + if (pFile!=NULL) fclose(pFile); + delete tagDir; +} + +DCPProfile::~DCPProfile() { + delete[] aDeltas1; + delete[] aDeltas2; + delete[] aLookTable; +} + +void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) const { + + // Apply the HueSatMap. Ported from Adobes reference implementation + float hueShift, satScale, valScale; + float vEncoded = v; + + if (ti.iValDivisions < 2) // Optimize most common case of "2.5D" table. + { + float hScaled = h * ti.pc.hScale; + float sScaled = s * ti.pc.sScale; + + int hIndex0 = max((int)hScaled, 0); + int sIndex0 = max(min((int)sScaled,ti.pc.maxSatIndex0),0); + + int hIndex1 = hIndex0 + 1; + + if (hIndex0 >= ti.pc.maxHueIndex0) + { + hIndex0 = ti.pc.maxHueIndex0; + hIndex1 = 0; + } + + float hFract1 = hScaled - (float) hIndex0; + float sFract1 = sScaled - (float) sIndex0; + + float hFract0 = 1.0f - hFract1; + float sFract0 = 1.0f - sFract1; + + const HSBModify *entry00 = tableBase + hIndex0 * ti.pc.hueStep + sIndex0; + const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep; + + float hueShift0 = hFract0 * entry00->fHueShift + hFract1 * entry01->fHueShift; + float satScale0 = hFract0 * entry00->fSatScale + hFract1 * entry01->fSatScale; + float valScale0 = hFract0 * entry00->fValScale + hFract1 * entry01->fValScale; + + entry00++; + entry01++; + + float hueShift1 = hFract0 * entry00->fHueShift + + hFract1 * entry01->fHueShift; + + float satScale1 = hFract0 * entry00->fSatScale + + hFract1 * entry01->fSatScale; + + float valScale1 = hFract0 * entry00->fValScale + + hFract1 * entry01->fValScale; + + hueShift = sFract0 * hueShift0 + sFract1 * hueShift1; + satScale = sFract0 * satScale0 + sFract1 * satScale1; + valScale = sFract0 * valScale0 + sFract1 * valScale1; + + } else { + + float hScaled = h * ti.pc.hScale; + float sScaled = s * ti.pc.sScale; + if (ti.sRGBGamma) vEncoded = sRGBGammaForward(v); + float vScaled = vEncoded * ti.pc.vScale; + + int hIndex0 = (int) hScaled; + int sIndex0 = max(min((int)sScaled,ti.pc.maxSatIndex0),0); + int vIndex0 = max(min((int)vScaled,ti.pc.maxValIndex0),0); + + int hIndex1 = hIndex0 + 1; + + if (hIndex0 >= ti.pc.maxHueIndex0) + { + hIndex0 = ti.pc.maxHueIndex0; + hIndex1 = 0; + } + + float hFract1 = hScaled - (float) hIndex0; + float sFract1 = sScaled - (float) sIndex0; + float vFract1 = vScaled - (float) vIndex0; + + float hFract0 = 1.0f - hFract1; + float sFract0 = 1.0f - sFract1; + float vFract0 = 1.0f - vFract1; + + const HSBModify *entry00 = tableBase + vIndex0 * ti.pc.valStep + hIndex0 * ti.pc.hueStep + sIndex0; + + const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep; + + const HSBModify *entry10 = entry00 + ti.pc.valStep; + const HSBModify *entry11 = entry01 + ti.pc.valStep; + + float hueShift0 = vFract0 * (hFract0 * entry00->fHueShift + + hFract1 * entry01->fHueShift) + + vFract1 * (hFract0 * entry10->fHueShift + + hFract1 * entry11->fHueShift); + + float satScale0 = vFract0 * (hFract0 * entry00->fSatScale + + hFract1 * entry01->fSatScale) + + vFract1 * (hFract0 * entry10->fSatScale + + hFract1 * entry11->fSatScale); + + float valScale0 = vFract0 * (hFract0 * entry00->fValScale + + hFract1 * entry01->fValScale) + + vFract1 * (hFract0 * entry10->fValScale + + hFract1 * entry11->fValScale); + + entry00++; + entry01++; + entry10++; + entry11++; + + float hueShift1 = vFract0 * (hFract0 * entry00->fHueShift + + hFract1 * entry01->fHueShift) + + vFract1 * (hFract0 * entry10->fHueShift + + hFract1 * entry11->fHueShift); + + float satScale1 = vFract0 * (hFract0 * entry00->fSatScale + + hFract1 * entry01->fSatScale) + + vFract1 * (hFract0 * entry10->fSatScale + + hFract1 * entry11->fSatScale); + + float valScale1 = vFract0 * (hFract0 * entry00->fValScale + + hFract1 * entry01->fValScale) + + vFract1 * (hFract0 * entry10->fValScale + + hFract1 * entry11->fValScale); + + hueShift = sFract0 * hueShift0 + sFract1 * hueShift1; + satScale = sFract0 * satScale0 + sFract1 * satScale1; + valScale = sFract0 * valScale0 + sFract1 * valScale1; + } + + hueShift *= (6.0f / 360.0f); // Convert to internal hue range. + + h += hueShift; + s *= satScale; // no clipping here, we are RT float :-) + if (ti.sRGBGamma) { + v = sRGBGammaInverse(vEncoded * valScale); + } else { + v *= valScale; + } +} + +struct ruvt { + double r; + double u; + double v; + double t; +}; + +static const double kTintScale = -3000.0; +static const ruvt kTempTable [] = + { + { 0, 0.18006, 0.26352, -0.24341 }, + { 10, 0.18066, 0.26589, -0.25479 }, + { 20, 0.18133, 0.26846, -0.26876 }, + { 30, 0.18208, 0.27119, -0.28539 }, + { 40, 0.18293, 0.27407, -0.30470 }, + { 50, 0.18388, 0.27709, -0.32675 }, + { 60, 0.18494, 0.28021, -0.35156 }, + { 70, 0.18611, 0.28342, -0.37915 }, + { 80, 0.18740, 0.28668, -0.40955 }, + { 90, 0.18880, 0.28997, -0.44278 }, + { 100, 0.19032, 0.29326, -0.47888 }, + { 125, 0.19462, 0.30141, -0.58204 }, + { 150, 0.19962, 0.30921, -0.70471 }, + { 175, 0.20525, 0.31647, -0.84901 }, + { 200, 0.21142, 0.32312, -1.0182 }, + { 225, 0.21807, 0.32909, -1.2168 }, + { 250, 0.22511, 0.33439, -1.4512 }, + { 275, 0.23247, 0.33904, -1.7298 }, + { 300, 0.24010, 0.34308, -2.0637 }, + { 325, 0.24702, 0.34655, -2.4681 }, + { 350, 0.25591, 0.34951, -2.9641 }, + { 375, 0.26400, 0.35200, -3.5814 }, + { 400, 0.27218, 0.35407, -4.3633 }, + { 425, 0.28039, 0.35577, -5.3762 }, + { 450, 0.28863, 0.35714, -6.7262 }, + { 475, 0.29685, 0.35823, -8.5955 }, + { 500, 0.30505, 0.35907, -11.324 }, + { 525, 0.31320, 0.35968, -15.628 }, + { 550, 0.32129, 0.36011, -23.325 }, + { 575, 0.32931, 0.36038, -40.770 }, + { 600, 0.33724, 0.36051, -116.45 } + }; + +void DCPProfile::dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const { + double fTemperature = 0; + double fTint = 0; + + // Convert to uv space. + double u = 2.0 * whiteXY[0] / (1.5 - whiteXY[0] + 6.0 * whiteXY[1]); + double v = 3.0 * whiteXY[1] / (1.5 - whiteXY[0] + 6.0 * whiteXY[1]); + + // Search for line pair coordinate is between. + double last_dt = 0.0; + double last_dv = 0.0; + double last_du = 0.0; + + for (uint32_t index = 1; index <= 30; index++) { + // Convert slope to delta-u and delta-v, with length 1. + double du = 1.0; + double dv = kTempTable [index] . t; + double len = sqrt (1.0 + dv * dv); + du /= len; + dv /= len; + + // Find delta from black body point to test coordinate. + double uu = u - kTempTable [index] . u; + double vv = v - kTempTable [index] . v; + + // Find distance above or below line. + double dt = - uu * dv + vv * du; + + // If below line, we have found line pair. + if (dt <= 0.0 || index == 30) { + // Find fractional weight of two lines. + if (dt > 0.0) + dt = 0.0; + dt = -dt; + double f; + if (index == 1) + { + f = 0.0; + } + else + { + f = dt / (last_dt + dt); + } + + // Interpolate the temperature. + fTemperature = 1.0E6 / (kTempTable [index - 1] . r * f + + kTempTable [index ] . r * (1.0 - f)); + + // Find delta from black body point to test coordinate. + uu = u - (kTempTable [index - 1] . u * f + + kTempTable [index ] . u * (1.0 - f)); + vv = v - (kTempTable [index - 1] . v * f + + kTempTable [index ] . v * (1.0 - f)); + // Interpolate vectors along slope. + du = du * (1.0 - f) + last_du * f; + dv = dv * (1.0 - f) + last_dv * f; + len = sqrt (du * du + dv * dv); + du /= len; + dv /= len; + + // Find distance along slope. + fTint = (uu * du + vv * dv) * kTintScale; + break; + } + // Try next line pair. + last_dt = dt; + last_du = du; + last_dv = dv; + } + if (temp != NULL) + *temp = fTemperature; + if (tint != NULL) + *tint = fTint; +} + +void DCPProfile::dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const { + + bool hasCol1 = hasColorMatrix1; + bool hasCol2 = hasColorMatrix2; + if (preferredIlluminant == 1) { + if (hasCol1) hasCol2 = false; + } else if (preferredIlluminant == 2) { + if (hasCol2) hasCol1 = false; + } + + // mix if we have two matrices + double mix; + if (hasCol1 && hasCol2) { + double wbtemp; + /* + Note: we're using DNG SDK reference code for XY to temperature translation to get the exact same mix as + the reference code does. + */ + dngref_XYCoord2Temperature(whiteXY, &wbtemp, NULL); + if (wbtemp <= temperature1) { + mix = 1.0; + } else if (wbtemp >= temperature2) { + mix = 0.0; + } else { + double invT = 1.0 / wbtemp; + mix = (invT - (1.0 / temperature2)) / ((1.0 / temperature1) - (1.0 / temperature2)); + } + } + + // Interpolate the color matrix. + double mCol[3][3]; + if (hasCol1 && hasCol2) { + // interpolate + if (mix >= 1.0) { + memcpy(mCol, mColorMatrix1, sizeof(mCol)); + } else if (mix <= 0.0) { + memcpy(mCol, mColorMatrix2, sizeof(mCol)); + } else { + Mix3x3(mColorMatrix1, mix, mColorMatrix2, 1.0 - mix, mCol); + } + } else if (hasCol1) { + memcpy(mCol, mColorMatrix1, sizeof(mCol)); + } else { + memcpy(mCol, mColorMatrix2, sizeof(mCol)); + } + memcpy(xyzToCamera, mCol, sizeof(mCol)); +} + +void DCPProfile::dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const { + const int kMaxPasses = 30; + double lastXY[2] = { 0.3457, 0.3585 }; // D50 + for (int pass = 0; pass < kMaxPasses; pass++) { + double xyzToCamera[3][3]; + dngref_FindXYZtoCamera(lastXY, preferredIlluminant, xyzToCamera); + + double invM[3][3], nextXYZ[3], nextXY[2]; + Invert3x3(xyzToCamera, invM); + Multiply3x3_v3(invM, neutral, nextXYZ); + XYZtoXY(nextXYZ, nextXY); + + if (fabs(nextXY[0] - lastXY[0]) + + fabs(nextXY[1] - lastXY[1]) < 0.0000001) + { + XY[0] = nextXY[0]; + XY[1] = nextXY[1]; + return; + } + // If we reach the limit without converging, we are most likely + // in a two value oscillation. So take the average of the last + // two estimates and give up. + if (pass == kMaxPasses - 1) { + nextXY[0] = (lastXY[0] + nextXY[0]) * 0.5; + nextXY[1] = (lastXY[1] + nextXY[1]) * 0.5; + } + lastXY[0] = nextXY[0]; + lastXY[1] = nextXY[1]; + } + XY[0] = lastXY[0]; + XY[1] = lastXY[1]; +} + +void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], bool useToneCurve, bool applyHueSatMap, bool applyLookTable) const { + + TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); + + double mXYZCAM[3][3]; // Camera RGB to XYZ D50 matrix + MakeXYZCAM(wb, pre_mul, camWbMatrix, preferredIlluminant, mXYZCAM); + HSBModify *deleteTableHandle; + const HSBModify *deltaBase = MakeHueSatMap(wb, preferredIlluminant, &deleteTableHandle); + if (!deltaBase) applyHueSatMap = false; + if (!aLookTable) applyLookTable = false; + + useToneCurve&=toneCurve; + + if (!applyHueSatMap && !applyLookTable && !useToneCurve) { + //===== The fast path: no LUT and not tone curve- Calculate matrix for direct conversion raw>working space + double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + mat[i][j] += mWork[i][k] * mXYZCAM[k][j]; + + // Apply the matrix part +#pragma omp parallel for + for (int y=0; yheight; y++) { + float newr, newg, newb; + for (int x=0; xwidth; x++) { + newr = mat[0][0]*pImg->r(y,x) + mat[0][1]*pImg->g(y,x) + mat[0][2]*pImg->b(y,x); + newg = mat[1][0]*pImg->r(y,x) + mat[1][1]*pImg->g(y,x) + mat[1][2]*pImg->b(y,x); + newb = mat[2][0]*pImg->r(y,x) + mat[2][1]*pImg->g(y,x) + mat[2][2]*pImg->b(y,x); + + pImg->r(y,x) = newr; pImg->g(y,x) = newg; pImg->b(y,x) = newb; + } + } + } + else { + //===== LUT available- Calculate matrix for conversion raw>ProPhoto + double m2ProPhoto[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + m2ProPhoto[i][j] += prophoto_xyz[i][k] * mXYZCAM[k][j]; + + double m2Work[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; + + // Convert to prophoto and apply LUT +#pragma omp parallel for + for (int y=0; yheight; y++) { + float newr, newg, newb, h,s,v,hs,ss,vs; + for (int x=0; xwidth; x++) { + newr = m2ProPhoto[0][0]*pImg->r(y,x) + m2ProPhoto[0][1]*pImg->g(y,x) + m2ProPhoto[0][2]*pImg->b(y,x); + newg = m2ProPhoto[1][0]*pImg->r(y,x) + m2ProPhoto[1][1]*pImg->g(y,x) + m2ProPhoto[1][2]*pImg->b(y,x); + newb = m2ProPhoto[2][0]*pImg->r(y,x) + m2ProPhoto[2][1]*pImg->g(y,x) + m2ProPhoto[2][2]*pImg->b(y,x); + + // if point is in negative area, just the matrix, but not the LUT + if ((applyHueSatMap || applyLookTable) && newr>=0 && newg>=0 && newb>=0) { + Color::rgb2hsv(newr, newg, newb, h , s, v); + h*=6.f; // RT calculates in [0,1] + + if (applyHueSatMap) { + HSDApply(DeltaInfo, deltaBase, h, s, v); + } + if (applyLookTable) { + HSDApply(LookInfo, aLookTable, h, s, v); + } + + // RT range correction + if (h < 0.0f) h += 6.0f; + if (h >= 6.0f) h -= 6.0f; + h/=6.f; + Color::hsv2rgb( h, s, v, newr, newg, newb); + } + // tone curve + if (useToneCurve) toneCurve.Apply(newr, newg, newb); + + pImg->r(y,x) = m2Work[0][0]*newr + m2Work[0][1]*newg + m2Work[0][2]*newb; + pImg->g(y,x) = m2Work[1][0]*newr + m2Work[1][1]*newg + m2Work[1][2]*newb; + pImg->b(y,x) = m2Work[2][0]*newr + m2Work[2][1]*newg + m2Work[2][2]*newb; + } + } + } + + if (deleteTableHandle) delete[] deleteTableHandle; +} + +void DCPProfile::setStep2ApplyState(Glib::ustring workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure) { + + applyState.useToneCurve = useToneCurve; + applyState.applyLookTable = applyLookTable; + applyState.blScale = 1.0; + if (!aLookTable) applyState.applyLookTable = false; + if (!hasToneCurve) applyState.useToneCurve = false; + if (hasBaselineExposureOffset && applyBaselineExposure) { + applyState.blScale = powf(2, baselineExposureOffset); + } + + if (workingSpace == "ProPhoto") { + applyState.alreadyProPhoto = true; + } else { + applyState.alreadyProPhoto = false; + TMatrix mWork; + + mWork = iccStore->workingSpaceMatrix (workingSpace); + memset(applyState.m2ProPhoto, 0, sizeof(applyState.m2ProPhoto)); + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + applyState.m2ProPhoto[i][j] += prophoto_xyz[i][k] * mWork[k][j]; + + mWork = iccStore->workingSpaceInverseMatrix (workingSpace); + memset(applyState.m2Work, 0, sizeof(applyState.m2Work)); + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<3; k++) + applyState.m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; + } +} + +void DCPProfile::step2ApplyTile(float *rc, float *gc, float *bc, int width, int height, int tileWidth) const { + +#define FCLIP(a) ((a)>0.0?((a)<65535.5?(a):65535.5):0.0) +#define CLIP01(a) ((a)>0?((a)<1?(a):1):0) + + float exp_scale = 1.0; + exp_scale *= applyState.blScale; + if (!applyState.useToneCurve && !applyState.applyLookTable) { + if (exp_scale == 1.0) { + return; + } + for (int y=0; y= 6.0f) h -= 6.0f; + h/=6.f; + Color::hsv2rgb( h, s, v, newr, newg, newb); + } + if (applyState.useToneCurve) { + toneCurve.Apply(newr, newg, newb); + } + + if (applyState.alreadyProPhoto) { + rc[y*tileWidth+x] = newr; + gc[y*tileWidth+x] = newg; + bc[y*tileWidth+x] = newb; + } else { + rc[y*tileWidth+x] = applyState.m2Work[0][0]*newr + applyState.m2Work[0][1]*newg + applyState.m2Work[0][2]*newb; + gc[y*tileWidth+x] = applyState.m2Work[1][0]*newr + applyState.m2Work[1][1]*newg + applyState.m2Work[1][2]*newb; + bc[y*tileWidth+x] = applyState.m2Work[2][0]*newr + applyState.m2Work[2][1]*newg + applyState.m2Work[2][2]*newb; + } + } + } + } +} + +// Generates as singleton +DCPStore* DCPStore::getInstance() +{ + static DCPStore* instance_ = 0; + if ( instance_ == 0 ) + { + static MyMutex smutex_; + MyMutex::MyLock lock(smutex_); + if ( instance_ == 0 ) + { + instance_ = new DCPStore(); + } + } + return instance_; +} + +// Reads all profiles from the given profiles dir +void DCPStore::init (Glib::ustring rtProfileDir) { + MyMutex::MyLock lock(mtx); + + fileStdProfiles.clear(); + + Glib::ustring rootDirName=rtProfileDir; + + if (rootDirName!="") { + std::deque qDirs; + + qDirs.push_front(rootDirName); + + while (!qDirs.empty()) { + // process directory + Glib::ustring dirname = qDirs.back(); + qDirs.pop_back(); + + Glib::Dir* dir = NULL; + try { + if (!safe_file_test (dirname, Glib::FILE_TEST_IS_DIR)) return; + dir = new Glib::Dir (dirname); + } + catch (Glib::Exception& fe) { + return; + } + dirname = dirname + "/"; + for (Glib::DirIterator i = dir->begin(); i!=dir->end(); ++i) { + Glib::ustring fname = dirname + *i; + Glib::ustring sname = *i; + // ignore directories + if (!safe_file_test (fname, Glib::FILE_TEST_IS_DIR)) { + size_t lastdot = sname.find_last_of ('.'); + if (lastdot!=Glib::ustring::npos && lastdot<=sname.size()-4 && (!sname.casefold().compare (lastdot, 4, ".dcp"))) { + Glib::ustring camShortName = sname.substr(0,lastdot).uppercase(); + fileStdProfiles[camShortName]=fname; // they will be loaded and cached on demand + } + } else qDirs.push_front(fname); // for later scanning + } + delete dir; + } + } +} + +DCPProfile* DCPStore::getProfile (Glib::ustring filename, bool isRTProfile) { + MyMutex::MyLock lock(mtx); + + std::map::iterator r = profileCache.find (filename); + if (r!=profileCache.end()) return r->second; + + // Add profile + profileCache[filename]=new DCPProfile(filename, isRTProfile); + + return profileCache[filename]; +} + +DCPProfile* DCPStore::getStdProfile(Glib::ustring camShortName) { + Glib::ustring name2=camShortName.uppercase(); + + // Warning: do NOT use map.find(), since it does not seem to work reliably here + for (std::map::iterator i=fileStdProfiles.begin();i!=fileStdProfiles.end();i++) + if (name2==(*i).first) return getProfile((*i).second, true); + + return NULL; +} + +bool DCPStore::isValidDCPFileName(Glib::ustring filename) const { + if (!safe_file_test (filename, Glib::FILE_TEST_EXISTS) || safe_file_test (filename, Glib::FILE_TEST_IS_DIR)) return false; + size_t pos=filename.find_last_of ('.'); + return pos>0 && (!filename.casefold().compare (pos, 4, ".dcp") || !filename.casefold().compare (pos, 4, ".dng")); +} diff --git a/rtengine/dcp.h b/rtengine/dcp.h index aeeb97e8b..5e0fe2f0c 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -1,115 +1,115 @@ -/* -* This file is part of RawTherapee. -* -* Copyright (c) 2012 Oliver Duis -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -*/ - -#ifndef _DCP_ -#define _DCP_ - -#include "imagefloat.h" -#include "curves.h" -#include "colortemp.h" -#include "../rtgui/threadutils.h" +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2012 Oliver Duis +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ + +#ifndef _DCP_ +#define _DCP_ + +#include "imagefloat.h" +#include "curves.h" +#include "colortemp.h" +#include "../rtgui/threadutils.h" #include -#include -#include - -namespace rtengine { - - class DCPProfile { - struct HSBModify - { - float fHueShift; - float fSatScale; - float fValScale; - }; - struct HSDTableInfo - { - int iHueDivisions, iSatDivisions, iValDivisions; - int iHueStep, iValStep, iArrayCount; - bool sRGBGamma; - struct - { - float hScale, sScale, vScale; - int maxHueIndex0, maxSatIndex0, maxValIndex0; - int hueStep, valStep; - } pc; - }; - - double mColorMatrix1[3][3],mColorMatrix2[3][3]; - bool hasColorMatrix1, hasColorMatrix2, hasForwardMatrix1, hasForwardMatrix2, hasToneCurve, hasBaselineExposureOffset, willInterpolate; - double mForwardMatrix1[3][3],mForwardMatrix2[3][3]; - double temperature1, temperature2; - double baselineExposureOffset; - HSBModify *aDeltas1,*aDeltas2,*aLookTable; - HSDTableInfo DeltaInfo,LookInfo; - short iLightSource1,iLightSource2; - - AdobeToneCurve toneCurve; - struct { - double m2ProPhoto[3][3]; - double m2Work[3][3]; - bool alreadyProPhoto; - bool useToneCurve; - bool applyLookTable; - float blScale; - } applyState; - - void dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const; - void dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const; - void dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const; - void MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const; - const HSBModify* MakeHueSatMap(ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const; - void HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) const; - - public: - DCPProfile(Glib::ustring fname, bool isRTProfile); - ~DCPProfile(); - - bool getHasToneCurve() { return hasToneCurve; } - bool getHasLookTable() { return !!aLookTable; } - bool getHasHueSatMap() { return !!aDeltas1; } - bool getHasBaselineExposureOffset() { return hasBaselineExposureOffset; } - void getIlluminants(int &i1, double &temp1, int &i2, double &temp2, bool &willInterpolate_) { i1 = iLightSource1; i2 = iLightSource2; temp1 = temperature1, temp2 = temperature2; willInterpolate_ = willInterpolate; }; - void Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camMatrix[3][3], bool useToneCurve=false, bool applyHueSatMap=true, bool applyLookTable=false) const; - void setStep2ApplyState(Glib::ustring workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure); - void step2ApplyTile(float *r, float *g, float *b, int width, int height, int tileWidth) const; - }; - - class DCPStore { - MyMutex mtx; - +#include +#include + +namespace rtengine { + + class DCPProfile { + struct HSBModify + { + float fHueShift; + float fSatScale; + float fValScale; + }; + struct HSDTableInfo + { + int iHueDivisions, iSatDivisions, iValDivisions; + int iHueStep, iValStep, iArrayCount; + bool sRGBGamma; + struct + { + float hScale, sScale, vScale; + int maxHueIndex0, maxSatIndex0, maxValIndex0; + int hueStep, valStep; + } pc; + }; + + double mColorMatrix1[3][3],mColorMatrix2[3][3]; + bool hasColorMatrix1, hasColorMatrix2, hasForwardMatrix1, hasForwardMatrix2, hasToneCurve, hasBaselineExposureOffset, willInterpolate; + double mForwardMatrix1[3][3],mForwardMatrix2[3][3]; + double temperature1, temperature2; + double baselineExposureOffset; + HSBModify *aDeltas1,*aDeltas2,*aLookTable; + HSDTableInfo DeltaInfo,LookInfo; + short iLightSource1,iLightSource2; + + AdobeToneCurve toneCurve; + struct { + double m2ProPhoto[3][3]; + double m2Work[3][3]; + bool alreadyProPhoto; + bool useToneCurve; + bool applyLookTable; + float blScale; + } applyState; + + void dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const; + void dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const; + void dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const; + void MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const; + const HSBModify* MakeHueSatMap(ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const; + void HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) const; + + public: + DCPProfile(Glib::ustring fname, bool isRTProfile); + ~DCPProfile(); + + bool getHasToneCurve() { return hasToneCurve; } + bool getHasLookTable() { return !!aLookTable; } + bool getHasHueSatMap() { return !!aDeltas1; } + bool getHasBaselineExposureOffset() { return hasBaselineExposureOffset; } + void getIlluminants(int &i1, double &temp1, int &i2, double &temp2, bool &willInterpolate_) { i1 = iLightSource1; i2 = iLightSource2; temp1 = temperature1, temp2 = temperature2; willInterpolate_ = willInterpolate; }; + void Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camMatrix[3][3], bool useToneCurve=false, bool applyHueSatMap=true, bool applyLookTable=false) const; + void setStep2ApplyState(Glib::ustring workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure); + void step2ApplyTile(float *r, float *g, float *b, int width, int height, int tileWidth) const; + }; + + class DCPStore { + MyMutex mtx; + // these contain standard profiles from RT. keys are all in uppercase, file path is value - std::map fileStdProfiles; - - // Maps file name to profile as cache - std::map profileCache; - - public: + std::map fileStdProfiles; + + // Maps file name to profile as cache + std::map profileCache; + + public: void init(Glib::ustring rtProfileDir); bool isValidDCPFileName(Glib::ustring filename) const; DCPProfile* getProfile(Glib::ustring filename, bool isRTProfile=false); DCPProfile* getStdProfile(Glib::ustring camShortName); - - static DCPStore* getInstance(); - }; - - #define dcpStore DCPStore::getInstance() + + static DCPStore* getInstance(); + }; + + #define dcpStore DCPStore::getInstance() } -#endif +#endif diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 3317a68bf..e79b821b1 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -1,404 +1,404 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2010 Fabio Suprani - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#ifndef DCRAW_H -#define DCRAW_H - -#include "myfile.h" -#include - - -class DCraw -{ -public: - typedef unsigned short ushort; - typedef unsigned char uchar; - typedef unsigned short (*dcrawImage_t)[4]; -#ifdef WIN32 - typedef __int64 INT64; - typedef unsigned __int64 UINT64; -#else - typedef long long INT64; - typedef unsigned long long UINT64; -#endif - - - DCraw() - :exif_base(-1) - ,ciff_base(-1) - ,ciff_len(0) - ,ifp(NULL),ofp(NULL) - ,order(0x4949) - ,ifname(NULL) - ,meta_data(NULL) - ,shot_select(0),multi_out(0) - ,float_raw_image(NULL) - ,image(NULL) - ,bright(1.),threshold(0.) - ,half_size(0),four_color_rgb(0),document_mode(0),highlight(0) - ,verbose(0) - ,use_auto_wb(0),use_camera_wb(0),use_camera_matrix(1) - ,output_color(1),output_bps(8),output_tiff(0),med_passes(0),no_auto_bright(0) - ,RT_whitelevel_from_constant(0) - ,RT_blacklevel_from_constant(0) - ,RT_matrix_from_constant(0) - ,getbithuff(this,ifp,zero_after_ff) - ,ph1_bithuff(this,ifp,order) - ,pana_bits(ifp,load_flags) - { - memset(&hbd, 0, sizeof(hbd)); - aber[0]=aber[1]=aber[2]=aber[3]=1; - gamm[0]=0.45;gamm[1]=4.5;gamm[2]=gamm[3]=gamm[4]=gamm[5]=0; - user_mul[0]=user_mul[1]=user_mul[2]=user_mul[3]=0; - greybox[0]=greybox[1]=0; greybox[2]=greybox[3]= UINT_MAX; - } - - //int main (int argc, const char **argv); -protected: - int exif_base, ciff_base, ciff_len; - IMFILE *ifp; - FILE *ofp; - short order; - const char *ifname; - char *meta_data, xtrans[6][6],xtrans_abs[6][6]; - char cdesc[5], desc[512], make[64], model[64], model2[64], model3[64], artist[64]; - float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len; - time_t timestamp; - unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id; - off_t strip_offset, data_offset; - off_t thumb_offset, meta_offset, profile_offset; - unsigned thumb_length, meta_length, profile_length; - unsigned thumb_misc, *oprof, fuji_layout, shot_select, multi_out; - unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress; - unsigned black, cblack[4102], maximum, mix_green, raw_color, zero_is_bad; - unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error; - unsigned tile_width, tile_length, gpsdata[32], load_flags; - ushort raw_height, raw_width, height, width, top_margin, left_margin; - ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height; - ushort *raw_image; - float * float_raw_image; - ushort white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4]; - int mask[8][4], flip, tiff_flip, colors; - double pixel_aspect; - double aber[4]; - double gamm[6]; - dcrawImage_t image; - float bright, threshold, user_mul[4]; - - int half_size, four_color_rgb, document_mode, highlight; - int verbose, use_auto_wb, use_camera_wb, use_camera_matrix; - int output_color, output_bps, output_tiff, med_passes; - int no_auto_bright; - unsigned greybox[4] ; - int RT_whitelevel_from_constant; - int RT_blacklevel_from_constant; - int RT_matrix_from_constant; - - float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; - - int histogram[4][0x2000]; - void (DCraw::*write_thumb)(), (DCraw::*write_fun)(); - void (DCraw::*load_raw)(), (DCraw::*thumb_load_raw)(); - jmp_buf failure; - - unsigned huff[1024]; // static inside foveon_decoder - - struct decode { - struct decode *branch[2]; - int leaf; - } first_decode[2048], *second_decode, *free_decode; - - struct tiff_ifd { - int width, height, bps, comp, phint, offset, flip, samples, bytes; - int tile_width, tile_length, sample_format, predictor; - } tiff_ifd[10]; - - struct ph1 { - int format, key_off, tag_21a; - int black, split_col, black_col, split_row, black_row; - float tag_210; - } ph1; - struct hbd { - off_t levels, unknown1, flatfield; - } hbd; - - struct jhead { - int bits, high, wide, clrs, sraw, psv, restart, vpred[6]; - ushort *huff[6], *free[4], *row; - }; - - struct tiff_tag { - ushort tag, type; - int count; - union { char c[4]; short s[2]; int i; } val; - }; - - struct tiff_hdr { - ushort order, magic; - int ifd; - ushort pad, ntag; - struct tiff_tag tag[23]; - int nextifd; - ushort pad2, nexif; - struct tiff_tag exif[4]; - ushort pad3, ngps; - struct tiff_tag gpst[10]; - short bps[4]; - int rat[10]; - unsigned gps[26]; - char desc[512], make[64], model[64], soft[32], date[20], artist[64]; - }; -protected: - -int fcol (int row, int col); -void merror (void *ptr, const char *where); -void derror(); -ushort sget2 (uchar *s); -ushort get2(); -unsigned sget4 (uchar *s); -unsigned get4(); -unsigned getint (int type); -float int_to_float (int i); -double getreal (int type); -void read_shorts (ushort *pixel, int count); -void cubic_spline(const int *x_, const int *y_, const int len); -void canon_600_fixed_wb (int temp); -int canon_600_color (int ratio[2], int mar); -void canon_600_auto_wb(); -void canon_600_coeff(); -void canon_600_load_raw(); -void canon_600_correct(); -int canon_s2is(); -void redcine_load_raw(); -void parse_redcine(); - -// getbithuff(int nbits, ushort *huff); -class getbithuff_t -{ -public: - getbithuff_t(DCraw *p,IMFILE *&i, unsigned &z):parent(p),bitbuf(0),vbits(0),reset(0),ifp(i),zero_after_ff(z){} - unsigned operator()(int nbits, ushort *huff); - -private: - void derror(){ - parent->derror(); - } - DCraw *parent; - unsigned bitbuf; - int vbits, reset; - IMFILE *&ifp; - unsigned &zero_after_ff; -}; -getbithuff_t getbithuff; - -ushort * make_decoder_ref (const uchar **source); -ushort * make_decoder (const uchar *source); -void crw_init_tables (unsigned table, ushort *huff[2]); -int canon_has_lowbits(); -void canon_load_raw(); -int ljpeg_start (struct jhead *jh, int info_only); -void ljpeg_end (struct jhead *jh); -int ljpeg_diff (ushort *huff); -ushort * ljpeg_row (int jrow, struct jhead *jh); -void lossless_jpeg_load_raw(); - -void canon_sraw_load_raw(); -void adobe_copy_pixel (unsigned row, unsigned col, ushort **rp); -void lossless_dng_load_raw(); -void packed_dng_load_raw(); -void deflate_dng_load_raw(); -void pentax_load_raw(); -void nikon_load_raw(); -int nikon_is_compressed(); -int nikon_e995(); -int nikon_e2100(); -void nikon_3700(); -int minolta_z2(); -void ppm_thumb(); -void ppm16_thumb(); -void layer_thumb(); -void rollei_thumb(); -void rollei_load_raw(); -int raw (unsigned row, unsigned col); -void phase_one_flat_field (int is_float, int nc); -void phase_one_correct(); -void phase_one_load_raw(); -void nikon_yuv_load_raw(); -void kodak_c330_load_raw(); -void kodak_c603_load_raw(); -void samsung3_load_raw(); -void parse_qt (int end); - -// ph1_bithuff(int nbits, ushort *huff); -class ph1_bithuff_t { -public: - ph1_bithuff_t(DCraw *p,IMFILE *&i,short &o):parent(p),order(o),ifp(i),bitbuf(0),vbits(0){} - unsigned operator()(int nbits, ushort *huff); -private: - unsigned get4(){ - return parent->get4(); - } - DCraw *parent; - short ℴ - IMFILE *&ifp; - UINT64 bitbuf; - int vbits; -}; -ph1_bithuff_t ph1_bithuff; - -void phase_one_load_raw_c(); -void hasselblad_correct(); -void parse_hasselblad_gain(); -void hasselblad_load_raw(); -void leaf_hdr_load_raw(); -void unpacked_load_raw(); -void sinar_4shot_load_raw(); -void imacon_full_load_raw(); -void packed_load_raw(); -void nokia_load_raw(); - -// pana_bits(int nbits); -class pana_bits_t{ -public: - pana_bits_t(IMFILE *&i,unsigned &u):ifp(i),load_flags(u){} - unsigned operator()(int nbits); -private: - IMFILE *&ifp; - unsigned &load_flags; - uchar buf[0x4000]; - int vbits; -}; -pana_bits_t pana_bits; - -void canon_rmf_load_raw(); -void panasonic_load_raw(); -void olympus_load_raw(); -void minolta_rd175_load_raw(); -void quicktake_100_load_raw(); -void kodak_radc_load_raw(); -void samsung_load_raw(); -void samsung2_load_raw(); -void kodak_jpeg_load_raw(); -void lossy_dng_load_raw(); -void kodak_dc120_load_raw(); -void eight_bit_load_raw(); -void kodak_yrgb_load_raw(); -void kodak_262_load_raw(); -int kodak_65000_decode (short *out, int bsize); -void kodak_65000_load_raw(); -void kodak_ycbcr_load_raw(); -void kodak_rgb_load_raw(); -void kodak_thumb_load_raw(); - -// sony_decrypt(unsigned *data, int len, int start, int key); -class sony_decrypt_t{ -public: - void operator()(unsigned *data, int len, int start, int key); -private: - unsigned pad[128], p; -}; -sony_decrypt_t sony_decrypt; - -void sony_load_raw(); -void sony_arw_load_raw(); -void sony_arw2_load_raw(); -void smal_decode_segment (unsigned seg[2][2], int holes); -void smal_v6_load_raw(); - -int median4 (int *p); -void fill_holes (int holes); -void smal_v9_load_raw(); - -void foveon_decoder (unsigned size, unsigned code); -void foveon_thumb(); -void foveon_sd_load_raw(); -void foveon_load_camf(); -void foveon_load_raw(); -void foveon_huff (ushort *huff); -void foveon_dp_load_raw(); -const char * foveon_camf_param (const char *block, const char *param); -void *foveon_camf_matrix (unsigned dim[3], const char *name); -int foveon_fixed (void *ptr, int size, const char *name); -float foveon_avg (short *pix, int range[2], float cfilt); -short *foveon_make_curve (double max, double mul, double filt); -void foveon_make_curves(short **curvep, float dq[3], float div[3], float filt); -int foveon_apply_curve (short *curve, int i); -void foveon_interpolate(); - -void xtrans_interpolate (int passes); -void cielab (ushort rgb[3], short lab[3]); - -void remove_zeroes(); -void bad_pixels (const char *cfname); -void subtract (const char *fname); -void gamma_curve (double pwr, double ts, int mode, int imax); -void pseudoinverse (double (*in)[3], double (*out)[3], int size); -void cam_xyz_coeff (float rgb_cam[3][4], double cam_xyz[4][3]); -void hat_transform (float *temp, float *base, int st, int size, int sc); -void wavelet_denoise(); -void scale_colors(); -void pre_interpolate(); -void border_interpolate (int border); -void median_filter(); -void blend_highlights(); -void recover_highlights(); -void crop_masked_pixels(); - -void tiff_get (unsigned base, unsigned *tag, unsigned *type, unsigned *len, unsigned *save); -void parse_thumb_note (int base, unsigned toff, unsigned tlen); -int parse_tiff_ifd (int base); -void parse_makernote (int base, int uptag); -void get_timestamp (int reversed); -void parse_exif (int base); -void parse_gps (int base); -void romm_coeff (float romm_cam[3][3]); -void parse_mos (int offset); -void linear_table (unsigned len); -void parse_kodak_ifd (int base); - -void parse_minolta (int base); -int parse_tiff (int base); -void apply_tiff(); -void parse_external_jpeg(); -void ciff_block_1030(); -void parse_ciff (int offset, int length, int depth); -void parse_rollei(); -void parse_sinar_ia(); -void parse_phase_one (int base); -void parse_fuji (int offset); -int parse_jpeg (int offset); -void parse_riff(); -void parse_smal (int offset, int fsize); -void parse_cine(); -char *foveon_gets (int offset, char *str, int len); -void parse_foveon(); - -void adobe_coeff (const char *make, const char *model); -void simple_coeff (int index); -short guess_byte_order (int words); -float find_green (int bps, int bite, int off0, int off1); -void identify(); -void apply_profile (const char *input, const char *output); -void jpeg_thumb() {} // not needed -bool dcraw_coeff_overrides(const char make[], const char model[], int iso_speed, short trans[12], int *black_level, int *white_level); - -}; - - -#endif //DCRAW_H +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2010 Fabio Suprani + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#ifndef DCRAW_H +#define DCRAW_H + +#include "myfile.h" +#include + + +class DCraw +{ +public: + typedef unsigned short ushort; + typedef unsigned char uchar; + typedef unsigned short (*dcrawImage_t)[4]; +#ifdef WIN32 + typedef __int64 INT64; + typedef unsigned __int64 UINT64; +#else + typedef long long INT64; + typedef unsigned long long UINT64; +#endif + + + DCraw() + :exif_base(-1) + ,ciff_base(-1) + ,ciff_len(0) + ,ifp(NULL),ofp(NULL) + ,order(0x4949) + ,ifname(NULL) + ,meta_data(NULL) + ,shot_select(0),multi_out(0) + ,float_raw_image(NULL) + ,image(NULL) + ,bright(1.),threshold(0.) + ,half_size(0),four_color_rgb(0),document_mode(0),highlight(0) + ,verbose(0) + ,use_auto_wb(0),use_camera_wb(0),use_camera_matrix(1) + ,output_color(1),output_bps(8),output_tiff(0),med_passes(0),no_auto_bright(0) + ,RT_whitelevel_from_constant(0) + ,RT_blacklevel_from_constant(0) + ,RT_matrix_from_constant(0) + ,getbithuff(this,ifp,zero_after_ff) + ,ph1_bithuff(this,ifp,order) + ,pana_bits(ifp,load_flags) + { + memset(&hbd, 0, sizeof(hbd)); + aber[0]=aber[1]=aber[2]=aber[3]=1; + gamm[0]=0.45;gamm[1]=4.5;gamm[2]=gamm[3]=gamm[4]=gamm[5]=0; + user_mul[0]=user_mul[1]=user_mul[2]=user_mul[3]=0; + greybox[0]=greybox[1]=0; greybox[2]=greybox[3]= UINT_MAX; + } + + //int main (int argc, const char **argv); +protected: + int exif_base, ciff_base, ciff_len; + IMFILE *ifp; + FILE *ofp; + short order; + const char *ifname; + char *meta_data, xtrans[6][6],xtrans_abs[6][6]; + char cdesc[5], desc[512], make[64], model[64], model2[64], model3[64], artist[64]; + float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len; + time_t timestamp; + unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id; + off_t strip_offset, data_offset; + off_t thumb_offset, meta_offset, profile_offset; + unsigned thumb_length, meta_length, profile_length; + unsigned thumb_misc, *oprof, fuji_layout, shot_select, multi_out; + unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress; + unsigned black, cblack[4102], maximum, mix_green, raw_color, zero_is_bad; + unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error; + unsigned tile_width, tile_length, gpsdata[32], load_flags; + ushort raw_height, raw_width, height, width, top_margin, left_margin; + ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height; + ushort *raw_image; + float * float_raw_image; + ushort white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4]; + int mask[8][4], flip, tiff_flip, colors; + double pixel_aspect; + double aber[4]; + double gamm[6]; + dcrawImage_t image; + float bright, threshold, user_mul[4]; + + int half_size, four_color_rgb, document_mode, highlight; + int verbose, use_auto_wb, use_camera_wb, use_camera_matrix; + int output_color, output_bps, output_tiff, med_passes; + int no_auto_bright; + unsigned greybox[4] ; + int RT_whitelevel_from_constant; + int RT_blacklevel_from_constant; + int RT_matrix_from_constant; + + float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; + + int histogram[4][0x2000]; + void (DCraw::*write_thumb)(), (DCraw::*write_fun)(); + void (DCraw::*load_raw)(), (DCraw::*thumb_load_raw)(); + jmp_buf failure; + + unsigned huff[1024]; // static inside foveon_decoder + + struct decode { + struct decode *branch[2]; + int leaf; + } first_decode[2048], *second_decode, *free_decode; + + struct tiff_ifd { + int width, height, bps, comp, phint, offset, flip, samples, bytes; + int tile_width, tile_length, sample_format, predictor; + } tiff_ifd[10]; + + struct ph1 { + int format, key_off, tag_21a; + int black, split_col, black_col, split_row, black_row; + float tag_210; + } ph1; + struct hbd { + off_t levels, unknown1, flatfield; + } hbd; + + struct jhead { + int bits, high, wide, clrs, sraw, psv, restart, vpred[6]; + ushort *huff[6], *free[4], *row; + }; + + struct tiff_tag { + ushort tag, type; + int count; + union { char c[4]; short s[2]; int i; } val; + }; + + struct tiff_hdr { + ushort order, magic; + int ifd; + ushort pad, ntag; + struct tiff_tag tag[23]; + int nextifd; + ushort pad2, nexif; + struct tiff_tag exif[4]; + ushort pad3, ngps; + struct tiff_tag gpst[10]; + short bps[4]; + int rat[10]; + unsigned gps[26]; + char desc[512], make[64], model[64], soft[32], date[20], artist[64]; + }; +protected: + +int fcol (int row, int col); +void merror (void *ptr, const char *where); +void derror(); +ushort sget2 (uchar *s); +ushort get2(); +unsigned sget4 (uchar *s); +unsigned get4(); +unsigned getint (int type); +float int_to_float (int i); +double getreal (int type); +void read_shorts (ushort *pixel, int count); +void cubic_spline(const int *x_, const int *y_, const int len); +void canon_600_fixed_wb (int temp); +int canon_600_color (int ratio[2], int mar); +void canon_600_auto_wb(); +void canon_600_coeff(); +void canon_600_load_raw(); +void canon_600_correct(); +int canon_s2is(); +void redcine_load_raw(); +void parse_redcine(); + +// getbithuff(int nbits, ushort *huff); +class getbithuff_t +{ +public: + getbithuff_t(DCraw *p,IMFILE *&i, unsigned &z):parent(p),bitbuf(0),vbits(0),reset(0),ifp(i),zero_after_ff(z){} + unsigned operator()(int nbits, ushort *huff); + +private: + void derror(){ + parent->derror(); + } + DCraw *parent; + unsigned bitbuf; + int vbits, reset; + IMFILE *&ifp; + unsigned &zero_after_ff; +}; +getbithuff_t getbithuff; + +ushort * make_decoder_ref (const uchar **source); +ushort * make_decoder (const uchar *source); +void crw_init_tables (unsigned table, ushort *huff[2]); +int canon_has_lowbits(); +void canon_load_raw(); +int ljpeg_start (struct jhead *jh, int info_only); +void ljpeg_end (struct jhead *jh); +int ljpeg_diff (ushort *huff); +ushort * ljpeg_row (int jrow, struct jhead *jh); +void lossless_jpeg_load_raw(); + +void canon_sraw_load_raw(); +void adobe_copy_pixel (unsigned row, unsigned col, ushort **rp); +void lossless_dng_load_raw(); +void packed_dng_load_raw(); +void deflate_dng_load_raw(); +void pentax_load_raw(); +void nikon_load_raw(); +int nikon_is_compressed(); +int nikon_e995(); +int nikon_e2100(); +void nikon_3700(); +int minolta_z2(); +void ppm_thumb(); +void ppm16_thumb(); +void layer_thumb(); +void rollei_thumb(); +void rollei_load_raw(); +int raw (unsigned row, unsigned col); +void phase_one_flat_field (int is_float, int nc); +void phase_one_correct(); +void phase_one_load_raw(); +void nikon_yuv_load_raw(); +void kodak_c330_load_raw(); +void kodak_c603_load_raw(); +void samsung3_load_raw(); +void parse_qt (int end); + +// ph1_bithuff(int nbits, ushort *huff); +class ph1_bithuff_t { +public: + ph1_bithuff_t(DCraw *p,IMFILE *&i,short &o):parent(p),order(o),ifp(i),bitbuf(0),vbits(0){} + unsigned operator()(int nbits, ushort *huff); +private: + unsigned get4(){ + return parent->get4(); + } + DCraw *parent; + short ℴ + IMFILE *&ifp; + UINT64 bitbuf; + int vbits; +}; +ph1_bithuff_t ph1_bithuff; + +void phase_one_load_raw_c(); +void hasselblad_correct(); +void parse_hasselblad_gain(); +void hasselblad_load_raw(); +void leaf_hdr_load_raw(); +void unpacked_load_raw(); +void sinar_4shot_load_raw(); +void imacon_full_load_raw(); +void packed_load_raw(); +void nokia_load_raw(); + +// pana_bits(int nbits); +class pana_bits_t{ +public: + pana_bits_t(IMFILE *&i,unsigned &u):ifp(i),load_flags(u){} + unsigned operator()(int nbits); +private: + IMFILE *&ifp; + unsigned &load_flags; + uchar buf[0x4000]; + int vbits; +}; +pana_bits_t pana_bits; + +void canon_rmf_load_raw(); +void panasonic_load_raw(); +void olympus_load_raw(); +void minolta_rd175_load_raw(); +void quicktake_100_load_raw(); +void kodak_radc_load_raw(); +void samsung_load_raw(); +void samsung2_load_raw(); +void kodak_jpeg_load_raw(); +void lossy_dng_load_raw(); +void kodak_dc120_load_raw(); +void eight_bit_load_raw(); +void kodak_yrgb_load_raw(); +void kodak_262_load_raw(); +int kodak_65000_decode (short *out, int bsize); +void kodak_65000_load_raw(); +void kodak_ycbcr_load_raw(); +void kodak_rgb_load_raw(); +void kodak_thumb_load_raw(); + +// sony_decrypt(unsigned *data, int len, int start, int key); +class sony_decrypt_t{ +public: + void operator()(unsigned *data, int len, int start, int key); +private: + unsigned pad[128], p; +}; +sony_decrypt_t sony_decrypt; + +void sony_load_raw(); +void sony_arw_load_raw(); +void sony_arw2_load_raw(); +void smal_decode_segment (unsigned seg[2][2], int holes); +void smal_v6_load_raw(); + +int median4 (int *p); +void fill_holes (int holes); +void smal_v9_load_raw(); + +void foveon_decoder (unsigned size, unsigned code); +void foveon_thumb(); +void foveon_sd_load_raw(); +void foveon_load_camf(); +void foveon_load_raw(); +void foveon_huff (ushort *huff); +void foveon_dp_load_raw(); +const char * foveon_camf_param (const char *block, const char *param); +void *foveon_camf_matrix (unsigned dim[3], const char *name); +int foveon_fixed (void *ptr, int size, const char *name); +float foveon_avg (short *pix, int range[2], float cfilt); +short *foveon_make_curve (double max, double mul, double filt); +void foveon_make_curves(short **curvep, float dq[3], float div[3], float filt); +int foveon_apply_curve (short *curve, int i); +void foveon_interpolate(); + +void xtrans_interpolate (int passes); +void cielab (ushort rgb[3], short lab[3]); + +void remove_zeroes(); +void bad_pixels (const char *cfname); +void subtract (const char *fname); +void gamma_curve (double pwr, double ts, int mode, int imax); +void pseudoinverse (double (*in)[3], double (*out)[3], int size); +void cam_xyz_coeff (float rgb_cam[3][4], double cam_xyz[4][3]); +void hat_transform (float *temp, float *base, int st, int size, int sc); +void wavelet_denoise(); +void scale_colors(); +void pre_interpolate(); +void border_interpolate (int border); +void median_filter(); +void blend_highlights(); +void recover_highlights(); +void crop_masked_pixels(); + +void tiff_get (unsigned base, unsigned *tag, unsigned *type, unsigned *len, unsigned *save); +void parse_thumb_note (int base, unsigned toff, unsigned tlen); +int parse_tiff_ifd (int base); +void parse_makernote (int base, int uptag); +void get_timestamp (int reversed); +void parse_exif (int base); +void parse_gps (int base); +void romm_coeff (float romm_cam[3][3]); +void parse_mos (int offset); +void linear_table (unsigned len); +void parse_kodak_ifd (int base); + +void parse_minolta (int base); +int parse_tiff (int base); +void apply_tiff(); +void parse_external_jpeg(); +void ciff_block_1030(); +void parse_ciff (int offset, int length, int depth); +void parse_rollei(); +void parse_sinar_ia(); +void parse_phase_one (int base); +void parse_fuji (int offset); +int parse_jpeg (int offset); +void parse_riff(); +void parse_smal (int offset, int fsize); +void parse_cine(); +char *foveon_gets (int offset, char *str, int len); +void parse_foveon(); + +void adobe_coeff (const char *make, const char *model); +void simple_coeff (int index); +short guess_byte_order (int words); +float find_green (int bps, int bite, int off0, int off1); +void identify(); +void apply_profile (const char *input, const char *output); +void jpeg_thumb() {} // not needed +bool dcraw_coeff_overrides(const char make[], const char model[], int iso_speed, short trans[12], int *black_level, int *white_level); + +}; + + +#endif //DCRAW_H diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index 42eae61bb..947542e50 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -1,179 +1,179 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "dfmanager.h" -#include "../rtgui/options.h" -#include -#include "../rtgui/guiutils.h" -#include "safegtk.h" -#include "rawimage.h" -#include -#include -#include +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "dfmanager.h" +#include "../rtgui/options.h" +#include +#include "../rtgui/guiutils.h" +#include "safegtk.h" +#include "rawimage.h" +#include +#include +#include #include "imagedata.h" -#include +#include -namespace rtengine{ - -extern const Settings* settings; - -// *********************** class dfInfo ************************************** - -inline dfInfo& dfInfo::operator =(const dfInfo &o){ - pathname = o.pathname; - maker = o.maker; - model = o.model; - iso = o.iso; - shutter = o.shutter; - timestamp = o.timestamp; - if( ri ){ - delete ri; - ri = NULL; - } - return *this; -} - -bool dfInfo::operator <(const dfInfo &e2) const -{ - if( this->maker.compare( e2.maker) >=0 ) - return false; - if( this->model.compare( e2.model) >=0 ) - return false; - if( this->iso >= e2.iso ) - return false; - if( this->shutter >= e2.shutter ) - return false; - if( this->timestamp >= e2.timestamp ) - return false; - return true; -} - -std::string dfInfo::key(const std::string &mak, const std::string &mod, int iso, double shut ) -{ - std::ostringstream s; - s << mak << " " << mod << " "; - s.width(5); - s << iso << "ISO "; - s.precision( 2 ); - s.width(4); - s << shut << "s"; - return s.str(); -} - -double dfInfo::distance(const std::string &mak, const std::string &mod, int iso, double shutter) const -{ - if( this->maker.compare( mak) != 0 ) - return INFINITY; - if( this->model.compare( mod) != 0 ) - return INFINITY; - double dISO= (log(this->iso/100.) - log(iso/100.))/log(2); - double dShutter = (log(this->shutter) - log(shutter))/log(2); - return sqrt( dISO*dISO + dShutter*dShutter); -} - -RawImage* dfInfo::getRawImage() -{ - if(ri) - return ri; - updateRawImage(); - updateBadPixelList( ri ); - - return ri; -} - -std::vector& dfInfo::getHotPixels() -{ - if( !ri ){ - updateRawImage(); - updateBadPixelList( ri ); - } - return badPixels; -} -/* updateRawImage() load into ri the actual pixel data from pathname if there is a single shot - * otherwise load each file from the pathNames list and extract a template from the media; - * the first file is used also for reading all information other than pixels - */ -void dfInfo::updateRawImage() +namespace rtengine{ + +extern const Settings* settings; + +// *********************** class dfInfo ************************************** + +inline dfInfo& dfInfo::operator =(const dfInfo &o){ + pathname = o.pathname; + maker = o.maker; + model = o.model; + iso = o.iso; + shutter = o.shutter; + timestamp = o.timestamp; + if( ri ){ + delete ri; + ri = NULL; + } + return *this; +} + +bool dfInfo::operator <(const dfInfo &e2) const { - typedef unsigned int acc_t; - if( !pathNames.empty() ){ - std::list::iterator iName = pathNames.begin(); - ri = new RawImage(*iName); // First file used also for extra pixels informations (width,height, shutter, filters etc.. ) - if( ri->loadRaw(true)){ - delete ri; - ri=NULL; - }else{ - int H = ri->get_height(); - int W = ri->get_width(); - ri->compress_image(); - int rSize = W*((ri->getSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS)?1:3); - acc_t **acc = new acc_t*[H]; - for( int row=0; rowdata[row][col]; - int nFiles = 1; // First file data already loaded - - for( iName++; iName != pathNames.end(); iName++){ - RawImage* temp = new RawImage(*iName); - if( !temp->loadRaw(true)){ - temp->compress_image(); //\ TODO would be better working on original, because is temporary - nFiles++; - if( ri->getSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS ){ - for( int row=0; rowdata[row][col]; - } - }else{ - for( int row=0; rowdata[row][3*col+0]; - acc[row][3*col+1] += temp->data[row][3*col+1]; - acc[row][3*col+2] += temp->data[row][3*col+2]; - } - } - } - } - delete temp; - } - for (int row = 0; row < H; row++){ - for (int col = 0; col < rSize; col++) - ri->data[row][col] = acc[row][col] / nFiles; - delete [] acc[row]; - } - delete [] acc; - } - }else{ - ri = new RawImage(pathname); - if( ri->loadRaw(true)){ - delete ri; - ri=NULL; - }else - ri->compress_image(); - } -} - -void dfInfo::updateBadPixelList( RawImage *df ) + if( this->maker.compare( e2.maker) >=0 ) + return false; + if( this->model.compare( e2.model) >=0 ) + return false; + if( this->iso >= e2.iso ) + return false; + if( this->shutter >= e2.shutter ) + return false; + if( this->timestamp >= e2.timestamp ) + return false; + return true; +} + +std::string dfInfo::key(const std::string &mak, const std::string &mod, int iso, double shut ) { - const float threshold=10.f/8.f; + std::ostringstream s; + s << mak << " " << mod << " "; + s.width(5); + s << iso << "ISO "; + s.precision( 2 ); + s.width(4); + s << shut << "s"; + return s.str(); +} + +double dfInfo::distance(const std::string &mak, const std::string &mod, int iso, double shutter) const +{ + if( this->maker.compare( mak) != 0 ) + return INFINITY; + if( this->model.compare( mod) != 0 ) + return INFINITY; + double dISO= (log(this->iso/100.) - log(iso/100.))/log(2); + double dShutter = (log(this->shutter) - log(shutter))/log(2); + return sqrt( dISO*dISO + dShutter*dShutter); +} + +RawImage* dfInfo::getRawImage() +{ + if(ri) + return ri; + updateRawImage(); + updateBadPixelList( ri ); + + return ri; +} + +std::vector& dfInfo::getHotPixels() +{ + if( !ri ){ + updateRawImage(); + updateBadPixelList( ri ); + } + return badPixels; +} +/* updateRawImage() load into ri the actual pixel data from pathname if there is a single shot + * otherwise load each file from the pathNames list and extract a template from the media; + * the first file is used also for reading all information other than pixels + */ +void dfInfo::updateRawImage() +{ + typedef unsigned int acc_t; + if( !pathNames.empty() ){ + std::list::iterator iName = pathNames.begin(); + ri = new RawImage(*iName); // First file used also for extra pixels informations (width,height, shutter, filters etc.. ) + if( ri->loadRaw(true)){ + delete ri; + ri=NULL; + }else{ + int H = ri->get_height(); + int W = ri->get_width(); + ri->compress_image(); + int rSize = W*((ri->getSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS)?1:3); + acc_t **acc = new acc_t*[H]; + for( int row=0; rowdata[row][col]; + int nFiles = 1; // First file data already loaded + + for( iName++; iName != pathNames.end(); iName++){ + RawImage* temp = new RawImage(*iName); + if( !temp->loadRaw(true)){ + temp->compress_image(); //\ TODO would be better working on original, because is temporary + nFiles++; + if( ri->getSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS ){ + for( int row=0; rowdata[row][col]; + } + }else{ + for( int row=0; rowdata[row][3*col+0]; + acc[row][3*col+1] += temp->data[row][3*col+1]; + acc[row][3*col+2] += temp->data[row][3*col+2]; + } + } + } + } + delete temp; + } + for (int row = 0; row < H; row++){ + for (int col = 0; col < rSize; col++) + ri->data[row][col] = acc[row][col] / nFiles; + delete [] acc[row]; + } + delete [] acc; + } + }else{ + ri = new RawImage(pathname); + if( ri->loadRaw(true)){ + delete ri; + ri=NULL; + }else + ri->compress_image(); + } +} + +void dfInfo::updateBadPixelList( RawImage *df ) +{ + const float threshold=10.f/8.f; if( ri->getSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS ){ std::vector badPixelsTemp; @@ -181,268 +181,268 @@ void dfInfo::updateBadPixelList( RawImage *df ) { std::vector badPixelsThread; #pragma omp for nowait - for( int row=2; rowget_height()-2; row++) - for( int col=2; col < df->get_width()-2; col++){ - float m = (df->data[row-2][col-2] + df->data[row-2][col] + df->data[row-2][col+2]+ - df->data[row][col-2] + df->data[row][col+2]+ - df->data[row+2][col-2] + df->data[row+2][col] + df->data[row+2][col+2]); - if( df->data[row][col] > m*threshold ) - badPixelsThread.push_back( badPix(col,row) ); + for( int row=2; rowget_height()-2; row++) + for( int col=2; col < df->get_width()-2; col++){ + float m = (df->data[row-2][col-2] + df->data[row-2][col] + df->data[row-2][col+2]+ + df->data[row][col-2] + df->data[row][col+2]+ + df->data[row+2][col-2] + df->data[row+2][col] + df->data[row+2][col+2]); + if( df->data[row][col] > m*threshold ) + badPixelsThread.push_back( badPix(col,row) ); } #pragma omp critical badPixelsTemp.insert(badPixelsTemp.end(),badPixelsThread.begin(),badPixelsThread.end()); } - badPixels.insert(badPixels.end(),badPixelsTemp.begin(),badPixelsTemp.end()); - }else{ - for( int row=1; rowget_height()-1; row++) - for( int col=1; col < df->get_width()-1; col++){ - float m[3]; - for( int c=0; c<3;c++){ - m[c] = (df->data[row-1][3*(col-1)+c] + df->data[row-1][3*col+c] + df->data[row-1][3*(col+1)+c]+ - df->data[row] [3*(col-1)+c] + df->data[row] [3*col+c]+ - df->data[row+1][3*(col-1)+c] + df->data[row+1][3*col+c] + df->data[row+1][3*(col+1)+c]); - } - if( df->data[row][3*col] > m[0]*threshold || df->data[row][3*col+1] > m[1]*threshold || df->data[row][3*col+2] > m[2]*threshold) - badPixels.push_back( badPix(col,row) ); - } - } - if( settings->verbose ){ - std::cout << "Extracted " << badPixels.size() << " pixels from darkframe:" << df->get_filename().c_str() << std::endl; - } -} - - -// ************************* class DFManager ********************************* - -void DFManager::init( Glib::ustring pathname ) -{ - std::vector names; - Glib::RefPtr dir = Gio::File::create_for_path (pathname); - if( dir && !dir->query_exists()) - return; - safe_build_file_list (dir, names, pathname); - - dfList.clear(); - bpList.clear(); + badPixels.insert(badPixels.end(),badPixelsTemp.begin(),badPixelsTemp.end()); + }else{ + for( int row=1; rowget_height()-1; row++) + for( int col=1; col < df->get_width()-1; col++){ + float m[3]; + for( int c=0; c<3;c++){ + m[c] = (df->data[row-1][3*(col-1)+c] + df->data[row-1][3*col+c] + df->data[row-1][3*(col+1)+c]+ + df->data[row] [3*(col-1)+c] + df->data[row] [3*col+c]+ + df->data[row+1][3*(col-1)+c] + df->data[row+1][3*col+c] + df->data[row+1][3*(col+1)+c]); + } + if( df->data[row][3*col] > m[0]*threshold || df->data[row][3*col+1] > m[1]*threshold || df->data[row][3*col+2] > m[2]*threshold) + badPixels.push_back( badPix(col,row) ); + } + } + if( settings->verbose ){ + std::cout << "Extracted " << badPixels.size() << " pixels from darkframe:" << df->get_filename().c_str() << std::endl; + } +} + + +// ************************* class DFManager ********************************* + +void DFManager::init( Glib::ustring pathname ) +{ + std::vector names; + Glib::RefPtr dir = Gio::File::create_for_path (pathname); + if( dir && !dir->query_exists()) + return; + safe_build_file_list (dir, names, pathname); + + dfList.clear(); + bpList.clear(); for (size_t i=0; i0 && settings->verbose) - printf("Loaded %s: %d pixels\n",names[i].c_str(),n); - continue; - } - try{ - addFileInfo(names[i]); - }catch( std::exception& e ){} - } - // Where multiple shots exist for same group, move filename to list - for( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ - dfInfo &i = iter->second; - if( !i.pathNames.empty() && !i.pathname.empty() ){ - i.pathNames.push_back( i.pathname ); - i.pathname.clear(); - } - if( settings->verbose ){ - if( !i.pathname.empty() ) - printf( "%s: %s\n",i.key().c_str(),i.pathname.c_str()); - else{ - printf( "%s: MEAN of \n ",i.key().c_str()); - for( std::list::iterator iter = i.pathNames.begin(); iter != i.pathNames.end();iter++ ) - printf( "%s, ", iter->c_str() ); - printf("\n"); - } - } - } - currentPath = pathname; - return; -} - -dfInfo *DFManager::addFileInfo(const Glib::ustring &filename ,bool pool ) -{ - Glib::RefPtr file = Gio::File::create_for_path(filename); - if (!file ) - return 0; - if( !file->query_exists()) - return 0; - Glib::RefPtr info = safe_query_file_info(file); - if (info && info->get_file_type() != Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || !options.fbShowHidden)) { + if (lastdot != Glib::ustring::npos && names[i].substr(lastdot) == ".badpixels" ){ + int n = scanBadPixelsFile( names[i] ); + if( n>0 && settings->verbose) + printf("Loaded %s: %d pixels\n",names[i].c_str(),n); + continue; + } + try{ + addFileInfo(names[i]); + }catch( std::exception& e ){} + } + // Where multiple shots exist for same group, move filename to list + for( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ + dfInfo &i = iter->second; + if( !i.pathNames.empty() && !i.pathname.empty() ){ + i.pathNames.push_back( i.pathname ); + i.pathname.clear(); + } + if( settings->verbose ){ + if( !i.pathname.empty() ) + printf( "%s: %s\n",i.key().c_str(),i.pathname.c_str()); + else{ + printf( "%s: MEAN of \n ",i.key().c_str()); + for( std::list::iterator iter = i.pathNames.begin(); iter != i.pathNames.end();iter++ ) + printf( "%s, ", iter->c_str() ); + printf("\n"); + } + } + } + currentPath = pathname; + return; +} + +dfInfo *DFManager::addFileInfo(const Glib::ustring &filename ,bool pool ) +{ + Glib::RefPtr file = Gio::File::create_for_path(filename); + if (!file ) + return 0; + if( !file->query_exists()) + return 0; + Glib::RefPtr info = safe_query_file_info(file); + if (info && info->get_file_type() != Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || !options.fbShowHidden)) { size_t lastdot = info->get_name().find_last_of ('.'); - if (options.is_extention_enabled(lastdot!=Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){ - RawImage ri(filename); - int res = ri.loadRaw(false); // Read informations about shot - if( !res ){ - dfList_t::iterator iter; - if(!pool){ - dfInfo n(filename,"","",0,0,0); - iter = dfList.insert(std::pair< std::string,dfInfo>( "", n ) ); - return &(iter->second); - } - RawMetaDataLocation rml; - rml.exifBase = ri.get_exifBase(); - rml.ciffBase = ri.get_ciffBase(); - rml.ciffLength = ri.get_ciffLen(); - ImageData idata(filename, &rml); - /* Files are added in the map, divided by same maker/model,ISO and shutter*/ - std::string key( dfInfo::key(((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(),idata.getISOSpeed(),idata.getShutterSpeed()) ); - iter = dfList.find( key ); - if( iter == dfList.end() ){ - dfInfo n(filename, ((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(),idata.getISOSpeed(),idata.getShutterSpeed(), idata.getDateTimeAsTS() ); - iter = dfList.insert(std::pair< std::string,dfInfo>( key,n ) ); - }else{ - while( iter != dfList.end() && iter->second.key() == key && ABS(iter->second.timestamp - idata.getDateTimeAsTS()) >60*60*6 ) // 6 hour difference - iter++; - - if( iter != dfList.end() ) - iter->second.pathNames.push_back( filename ); - else{ - dfInfo n(filename, ((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(),idata.getISOSpeed(),idata.getShutterSpeed(),idata.getDateTimeAsTS()); - iter = dfList.insert(std::pair< std::string,dfInfo>( key,n ) ); - } - } - return &(iter->second); - } - } - } - return 0; -} - -void DFManager::getStat( int &totFiles, int &totTemplates) -{ - totFiles=0; - totTemplates=0; - for( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ - dfInfo &i = iter->second; - if( i.pathname.empty() ){ - totTemplates++; - totFiles += i.pathNames.size(); - }else - totFiles++; - } -} - -/* The search for the best match is twofold: - * if perfect matches for iso and shutter are found, then the list is scanned for lesser distance in time - * otherwise if no match is found, the whole list is searched for lesser distance in iso and shutter - */ -dfInfo* DFManager::find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ) -{ - if( dfList.empty() ) - return 0; - std::string key( dfInfo::key(mak,mod,isospeed,shut) ); - dfList_t::iterator iter = dfList.find( key ); - - if( iter != dfList.end() ){ - dfList_t::iterator bestMatch = iter; - time_t bestDeltaTime = ABS(iter->second.timestamp - t); - for(iter++; iter != dfList.end() && !key.compare( iter->second.key() ); iter++ ){ - time_t d = ABS(iter->second.timestamp - t ); - if( d< bestDeltaTime ){ - bestMatch = iter; - bestDeltaTime = d; - } - } - return &(bestMatch->second); - }else{ - iter = dfList.begin(); - dfList_t::iterator bestMatch = iter; - double bestD = iter->second.distance( mak, mod, isospeed, shut ); - for( iter++; iter != dfList.end();iter++ ){ - double d = iter->second.distance( mak, mod, isospeed, shut ); - if( d < bestD ){ - bestD = d; - bestMatch = iter; - } - } - return bestD != INFINITY ? &(bestMatch->second) : 0 ; - } -} - -RawImage* DFManager::searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) -{ - dfInfo *df = find( ((Glib::ustring)mak).uppercase(), ((Glib::ustring)mod).uppercase(), iso, shut, t ); - if( df ) - return df->getRawImage(); - else - return 0; -} - -RawImage* DFManager::searchDarkFrame( const Glib::ustring filename ) -{ - for ( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ - if( iter->second.pathname.compare( filename )==0 ) - return iter->second.getRawImage(); - } - dfInfo *df = addFileInfo( filename, false ); - if(df) - return df->getRawImage(); - return 0; -} -std::vector *DFManager::getHotPixels ( const Glib::ustring filename ) -{ - for ( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ - if( iter->second.pathname.compare( filename )==0 ) - return &iter->second.getHotPixels(); - } - return 0; -} -std::vector *DFManager::getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) -{ - dfInfo *df = find( ((Glib::ustring)mak).uppercase(), ((Glib::ustring)mod).uppercase(), iso, shut, t ); - if( df ){ - if( settings->verbose ) { - if( !df->pathname.empty() ) { - printf( "Searched hotpixels from %s\n",df->pathname.c_str()); - } else { - if( !df->pathNames.empty() ) { - printf( "Searched hotpixels from template (first %s)\n",df->pathNames.begin()->c_str()); - } - } - } - return &df->getHotPixels(); - }else - return 0; -} - -int DFManager::scanBadPixelsFile( Glib::ustring filename ) -{ - FILE *file = fopen( filename.c_str(),"r" ); - if( !file ) return false; + if (options.is_extention_enabled(lastdot!=Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){ + RawImage ri(filename); + int res = ri.loadRaw(false); // Read informations about shot + if( !res ){ + dfList_t::iterator iter; + if(!pool){ + dfInfo n(filename,"","",0,0,0); + iter = dfList.insert(std::pair< std::string,dfInfo>( "", n ) ); + return &(iter->second); + } + RawMetaDataLocation rml; + rml.exifBase = ri.get_exifBase(); + rml.ciffBase = ri.get_ciffBase(); + rml.ciffLength = ri.get_ciffLen(); + ImageData idata(filename, &rml); + /* Files are added in the map, divided by same maker/model,ISO and shutter*/ + std::string key( dfInfo::key(((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(),idata.getISOSpeed(),idata.getShutterSpeed()) ); + iter = dfList.find( key ); + if( iter == dfList.end() ){ + dfInfo n(filename, ((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(),idata.getISOSpeed(),idata.getShutterSpeed(), idata.getDateTimeAsTS() ); + iter = dfList.insert(std::pair< std::string,dfInfo>( key,n ) ); + }else{ + while( iter != dfList.end() && iter->second.key() == key && ABS(iter->second.timestamp - idata.getDateTimeAsTS()) >60*60*6 ) // 6 hour difference + iter++; + + if( iter != dfList.end() ) + iter->second.pathNames.push_back( filename ); + else{ + dfInfo n(filename, ((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(),idata.getISOSpeed(),idata.getShutterSpeed(),idata.getDateTimeAsTS()); + iter = dfList.insert(std::pair< std::string,dfInfo>( key,n ) ); + } + } + return &(iter->second); + } + } + } + return 0; +} + +void DFManager::getStat( int &totFiles, int &totTemplates) +{ + totFiles=0; + totTemplates=0; + for( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ + dfInfo &i = iter->second; + if( i.pathname.empty() ){ + totTemplates++; + totFiles += i.pathNames.size(); + }else + totFiles++; + } +} + +/* The search for the best match is twofold: + * if perfect matches for iso and shutter are found, then the list is scanned for lesser distance in time + * otherwise if no match is found, the whole list is searched for lesser distance in iso and shutter + */ +dfInfo* DFManager::find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ) +{ + if( dfList.empty() ) + return 0; + std::string key( dfInfo::key(mak,mod,isospeed,shut) ); + dfList_t::iterator iter = dfList.find( key ); + + if( iter != dfList.end() ){ + dfList_t::iterator bestMatch = iter; + time_t bestDeltaTime = ABS(iter->second.timestamp - t); + for(iter++; iter != dfList.end() && !key.compare( iter->second.key() ); iter++ ){ + time_t d = ABS(iter->second.timestamp - t ); + if( d< bestDeltaTime ){ + bestMatch = iter; + bestDeltaTime = d; + } + } + return &(bestMatch->second); + }else{ + iter = dfList.begin(); + dfList_t::iterator bestMatch = iter; + double bestD = iter->second.distance( mak, mod, isospeed, shut ); + for( iter++; iter != dfList.end();iter++ ){ + double d = iter->second.distance( mak, mod, isospeed, shut ); + if( d < bestD ){ + bestD = d; + bestMatch = iter; + } + } + return bestD != INFINITY ? &(bestMatch->second) : 0 ; + } +} + +RawImage* DFManager::searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) +{ + dfInfo *df = find( ((Glib::ustring)mak).uppercase(), ((Glib::ustring)mod).uppercase(), iso, shut, t ); + if( df ) + return df->getRawImage(); + else + return 0; +} + +RawImage* DFManager::searchDarkFrame( const Glib::ustring filename ) +{ + for ( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ + if( iter->second.pathname.compare( filename )==0 ) + return iter->second.getRawImage(); + } + dfInfo *df = addFileInfo( filename, false ); + if(df) + return df->getRawImage(); + return 0; +} +std::vector *DFManager::getHotPixels ( const Glib::ustring filename ) +{ + for ( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ + if( iter->second.pathname.compare( filename )==0 ) + return &iter->second.getHotPixels(); + } + return 0; +} +std::vector *DFManager::getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) +{ + dfInfo *df = find( ((Glib::ustring)mak).uppercase(), ((Glib::ustring)mod).uppercase(), iso, shut, t ); + if( df ){ + if( settings->verbose ) { + if( !df->pathname.empty() ) { + printf( "Searched hotpixels from %s\n",df->pathname.c_str()); + } else { + if( !df->pathNames.empty() ) { + printf( "Searched hotpixels from template (first %s)\n",df->pathNames.begin()->c_str()); + } + } + } + return &df->getHotPixels(); + }else + return 0; +} + +int DFManager::scanBadPixelsFile( Glib::ustring filename ) +{ + FILE *file = fopen( filename.c_str(),"r" ); + if( !file ) return false; size_t lastdot = filename.find_last_of ('.'); size_t dirpos1 = filename.find_last_of ('/'); size_t dirpos2 = filename.find_last_of ('\\'); - if( dirpos1 == Glib::ustring::npos && dirpos2== Glib::ustring::npos ) - dirpos1 =0; - else if( dirpos1 != Glib::ustring::npos && dirpos2 != Glib::ustring::npos ) - dirpos1= (dirpos1> dirpos2 ? dirpos1: dirpos2); - else if( dirpos1 == Glib::ustring::npos ) - dirpos1= dirpos2; - - std::string makmodel(filename,dirpos1+1,lastdot-(dirpos1+1) ); - std::vector bp; + if( dirpos1 == Glib::ustring::npos && dirpos2== Glib::ustring::npos ) + dirpos1 =0; + else if( dirpos1 != Glib::ustring::npos && dirpos2 != Glib::ustring::npos ) + dirpos1= (dirpos1> dirpos2 ? dirpos1: dirpos2); + else if( dirpos1 == Glib::ustring::npos ) + dirpos1= dirpos2; + + std::string makmodel(filename,dirpos1+1,lastdot-(dirpos1+1) ); + std::vector bp; char line[256]; if(fgets(line,sizeof(line),file )) { int x,y; int offset = 0; - int numparms = sscanf(line,"%d %d",&x,&y); + int numparms = sscanf(line,"%d %d",&x,&y); if( numparms == 1 ) // only one number in first line means, that this is the offset. offset = x; - else if(numparms == 2) + else if(numparms == 2) bp.push_back( badPix(x+offset,y+offset) ); - while( fgets(line,sizeof(line),file ) ){ - if( sscanf(line,"%d %d",&x,&y) == 2 ) - bp.push_back( badPix(x+offset,y+offset) ); - } - } - int numPixels = bp.size(); + while( fgets(line,sizeof(line),file ) ){ + if( sscanf(line,"%d %d",&x,&y) == 2 ) + bp.push_back( badPix(x+offset,y+offset) ); + } + } + int numPixels = bp.size(); if( numPixels >0 ) - bpList[ makmodel ] = bp; - fclose(file); - return numPixels; -} - -std::vector *DFManager::getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial) -{ + bpList[ makmodel ] = bp; + fclose(file); + return numPixels; +} + +std::vector *DFManager::getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial) +{ bpList_t::iterator iter; bool found = false; if( !serial.empty() ) { @@ -477,11 +477,11 @@ std::vector *DFManager::getBadPixels ( const std::string &mak, const std } else { return &(iter->second); } -} - -// Global variable -DFManager dfm; - - -} - +} + +// Global variable +DFManager dfm; + + +} + diff --git a/rtengine/dfmanager.h b/rtengine/dfmanager.h index 11d110cc3..784e70290 100644 --- a/rtengine/dfmanager.h +++ b/rtengine/dfmanager.h @@ -1,94 +1,94 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include -#include -#include -#include -#include "rawimage.h" - -namespace rtengine{ - -class dfInfo -{ -public: - - Glib::ustring pathname; // filename of dark frame - std::list pathNames; // other similar dark frames, used for average - std::string maker; ///< manufacturer - std::string model; ///< model - int iso; ///< ISO (gain) - double shutter; ///< shutter or exposure time in sec - time_t timestamp; ///< seconds since 1 Jan 1970 - - - dfInfo(const Glib::ustring &name, const std::string &mak, const std::string &mod,int iso,double shut,time_t t) - :pathname(name),maker(mak),model(mod),iso(iso),shutter(shut),timestamp(t),ri(NULL){} - - dfInfo( const dfInfo &o) - :pathname(o.pathname),maker(o.maker),model(o.model),iso(o.iso),shutter(o.shutter),timestamp(o.timestamp),ri(NULL){} - ~dfInfo() { if( ri ) delete ri; } - - - dfInfo &operator =(const dfInfo &o); - bool operator <(const dfInfo &e2) const; - - // Calculate virtual distance between two shots; different model return infinite - double distance(const std::string &mak, const std::string &mod, int iso, double shutter) const; - - static std::string key(const std::string &mak, const std::string &mod, int iso, double shut ); - std::string key(){ return key( maker,model,iso,shutter); } - - RawImage *getRawImage(); - std::vector &getHotPixels(); - -protected: - RawImage *ri; ///< Dark Frame raw data - std::vector badPixels; ///< Extracted hot pixels - - void updateBadPixelList( RawImage *df ); - void updateRawImage(); -}; - -class DFManager -{ -public: - void init( Glib::ustring pathname ); - Glib::ustring getPathname(){ return currentPath; }; - void getStat( int &totFiles, int &totTemplate); - RawImage *searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ); - RawImage *searchDarkFrame( const Glib::ustring filename ); - std::vector *getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ); - std::vector *getHotPixels ( const Glib::ustring filename ); - std::vector *getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial); - -protected: - typedef std::multimap dfList_t; - typedef std::map > bpList_t; - dfList_t dfList; - bpList_t bpList; - bool initialized; - Glib::ustring currentPath; - dfInfo *addFileInfo(const Glib::ustring &filename, bool pool=true ); - dfInfo *find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ); - int scanBadPixelsFile( Glib::ustring filename ); -}; - -extern DFManager dfm; - -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include +#include +#include +#include +#include "rawimage.h" + +namespace rtengine{ + +class dfInfo +{ +public: + + Glib::ustring pathname; // filename of dark frame + std::list pathNames; // other similar dark frames, used for average + std::string maker; ///< manufacturer + std::string model; ///< model + int iso; ///< ISO (gain) + double shutter; ///< shutter or exposure time in sec + time_t timestamp; ///< seconds since 1 Jan 1970 + + + dfInfo(const Glib::ustring &name, const std::string &mak, const std::string &mod,int iso,double shut,time_t t) + :pathname(name),maker(mak),model(mod),iso(iso),shutter(shut),timestamp(t),ri(NULL){} + + dfInfo( const dfInfo &o) + :pathname(o.pathname),maker(o.maker),model(o.model),iso(o.iso),shutter(o.shutter),timestamp(o.timestamp),ri(NULL){} + ~dfInfo() { if( ri ) delete ri; } + + + dfInfo &operator =(const dfInfo &o); + bool operator <(const dfInfo &e2) const; + + // Calculate virtual distance between two shots; different model return infinite + double distance(const std::string &mak, const std::string &mod, int iso, double shutter) const; + + static std::string key(const std::string &mak, const std::string &mod, int iso, double shut ); + std::string key(){ return key( maker,model,iso,shutter); } + + RawImage *getRawImage(); + std::vector &getHotPixels(); + +protected: + RawImage *ri; ///< Dark Frame raw data + std::vector badPixels; ///< Extracted hot pixels + + void updateBadPixelList( RawImage *df ); + void updateRawImage(); +}; + +class DFManager +{ +public: + void init( Glib::ustring pathname ); + Glib::ustring getPathname(){ return currentPath; }; + void getStat( int &totFiles, int &totTemplate); + RawImage *searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ); + RawImage *searchDarkFrame( const Glib::ustring filename ); + std::vector *getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ); + std::vector *getHotPixels ( const Glib::ustring filename ); + std::vector *getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial); + +protected: + typedef std::multimap dfList_t; + typedef std::map > bpList_t; + dfList_t dfList; + bpList_t bpList; + bool initialized; + Glib::ustring currentPath; + dfInfo *addFileInfo(const Glib::ustring &filename, bool pool=true ); + dfInfo *find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ); + int scanBadPixelsFile( Glib::ustring filename ); +}; + +extern DFManager dfm; + +} diff --git a/rtengine/expo_before_b.cc b/rtengine/expo_before_b.cc index 07dfc2e93..5c86fd786 100644 --- a/rtengine/expo_before_b.cc +++ b/rtengine/expo_before_b.cc @@ -1,153 +1,153 @@ - -//////////////////////////////////////////////////////////////// -// -// //exposure correction before interpolation -// -// code dated: December 27, 2010 -// -// Expo_before.cc is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -//////////////////////////////////////////////////////////////// - - - -// Jacques Desmis -// use fast-demo(provisional) from Emil Martinec + +//////////////////////////////////////////////////////////////// +// +// //exposure correction before interpolation +// +// code dated: December 27, 2010 +// +// Expo_before.cc is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +//////////////////////////////////////////////////////////////// + + + +// Jacques Desmis +// use fast-demo(provisional) from Emil Martinec // inspired from work Guillermo Luijk and Manuel LLorens(Perfectraw) // Ingo Weyrich (2014-07-07) // optimized the highlight protection case // needs 2*width*height*sizeof(float) byte less memory than before -// needs about 60% less processing time than before -// -// This function uses parameters: -// exposure (linear): 2^(-8..0..8): currently 0.5 +3 -// preserve (log) : 0..8 : currently 0.1 1 - -#include "rtengine.h" -#include "rawimagesource.h" -#include "mytime.h" -#include "rt_math.h" - -namespace rtengine { - -extern const Settings* settings; - -void RawImageSource::processRawWhitepoint(float expos, float preser) { - MyTime t1e,t2e; +// needs about 60% less processing time than before +// +// This function uses parameters: +// exposure (linear): 2^(-8..0..8): currently 0.5 +3 +// preserve (log) : 0..8 : currently 0.1 1 + +#include "rtengine.h" +#include "rawimagesource.h" +#include "mytime.h" +#include "rt_math.h" + +namespace rtengine { + +extern const Settings* settings; + +void RawImageSource::processRawWhitepoint(float expos, float preser) { + MyTime t1e,t2e; if (settings->verbose) - t1e.set(); - - int width=W, height=H; - // exposure correction inspired from G.Luijk + t1e.set(); + + int width=W, height=H; + // exposure correction inspired from G.Luijk for (int c=0; c<4; c++) - chmax[c] *= expos; + chmax[c] *= expos; - if (fabs(preser)<0.001f) { - // No highlight protection - simple mutiplication - - if (ri->getSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS) - #pragma omp parallel for - for (int row=0;rowgetSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS) { - // Demosaic to allow calculation of luminosity. - if(ri->getSensorType()==ST_BAYER) - fast_demosaic (0,0,W,H); - else - fast_xtrans_interpolate(); - } - - // Find maximum to adjust LUTs. New float engines clips only at the very end - float maxValFloat = 0.f; -#pragma omp parallel -{ - float maxValFloatThr = 0.f; - if (ri->getSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS) -#pragma omp for schedule(dynamic,16) nowait - for(int row=0;rowmaxValFloatThr) - maxValFloatThr = rawData[row][col]; - } - else -#pragma omp for schedule(dynamic,16) nowait - for(int row=0;rowgetSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS) + #pragma omp parallel for + for (int row=0;rowgetSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS) { + // Demosaic to allow calculation of luminosity. + if(ri->getSensorType()==ST_BAYER) + fast_demosaic (0,0,W,H); + else + fast_xtrans_interpolate(); + } + + // Find maximum to adjust LUTs. New float engines clips only at the very end + float maxValFloat = 0.f; +#pragma omp parallel +{ + float maxValFloatThr = 0.f; + if (ri->getSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS) +#pragma omp for schedule(dynamic,16) nowait + for(int row=0;rowmaxValFloatThr) + maxValFloatThr = rawData[row][col]; + } + else +#pragma omp for schedule(dynamic,16) nowait + for(int row=0;rowmaxValFloatThr) - maxValFloatThr = rawData[row][col*3+c]; - } - -#pragma omp critical -{ - if(maxValFloatThr > maxValFloat) - maxValFloat = maxValFloatThr; -} -} - - // Exposure correction with highlight preservation - int maxVal = maxValFloat; - LUTf lut(maxVal+1); - float K; + if (rawData[row][col*3+c]>maxValFloatThr) + maxValFloatThr = rawData[row][col*3+c]; + } + +#pragma omp critical +{ + if(maxValFloatThr > maxValFloat) + maxValFloat = maxValFloatThr; +} +} + + // Exposure correction with highlight preservation + int maxVal = maxValFloat; + LUTf lut(maxVal+1); + float K; if(expos>1){ - // Positive exposure - K = (float) maxVal / expos*exp(-preser*log(2.0)); - for (int j=max(1,(int)K);j<=maxVal;j++) + // Positive exposure + K = (float) maxVal / expos*exp(-preser*log(2.0)); + for (int j=max(1,(int)K);j<=maxVal;j++) lut[(int)j]=(((float)maxVal-K*expos)/((float)maxVal-K)*(j-maxVal)+(float) maxVal) / j; - } else { - // Negative exposure - float EV=log(expos)/log(2.0); // Convert exp. linear to EV - K = (float)maxVal * exp(-preser * log(2.0)); - - for (int j=0;j<=maxVal;j++) - lut[(int)j] = exp(EV*((float)maxVal-j) / ((float)maxVal-K) * log(2.0)); - } - - if (ri->getSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS) - #pragma omp parallel for schedule(dynamic,16) - for(int row=0;rowgetSensorType()==ST_BAYER || ri->getSensorType()==ST_FUJI_XTRANS) + #pragma omp parallel for schedule(dynamic,16) + for(int row=0;rowverbose) { - t2e.set(); + t2e.set(); printf("Exposure before %d usec\n", t2e.etime(t1e)); - } - -} - -} //namespace + } + +} + +} //namespace diff --git a/rtengine/gauss.h b/rtengine/gauss.h index 0c16f2a5e..8029b3976 100644 --- a/rtengine/gauss.h +++ b/rtengine/gauss.h @@ -27,10 +27,10 @@ #include #endif #ifdef __SSE__ -#if defined( WIN32 ) && defined(__x86_64__) - #include -#else - #include +#if defined( WIN32 ) && defined(__x86_64__) + #include +#else + #include #endif #endif @@ -76,103 +76,103 @@ template void gaussVertical3 (T** src, T** dst, AlignedBufferMP dst[H-1][i] = src[H-1][i]; } } - + #ifdef __SSE__ -#ifdef WIN32 +#ifdef WIN32 template __attribute__((force_align_arg_pointer)) void gaussVertical3Sse (T** src, T** dst, int W, int H, const float c0, const float c1) { #else template void gaussVertical3Sse (T** src, T** dst, int W, int H, const float c0, const float c1) { #endif - __m128 Tv,Tm1v,Tp1v; - __m128 c0v,c1v; - c0v = _mm_set1_ps(c0); - c1v = _mm_set1_ps(c1); + __m128 Tv,Tm1v,Tp1v; + __m128 c0v,c1v; + c0v = _mm_set1_ps(c0); + c1v = _mm_set1_ps(c1); #ifdef _OPENMP #pragma omp for -#endif - for (int i=0; i1) + if(H>1) Tv = _mm_loadu_ps( &src[1][i]); - for (int j=1; j __attribute__((force_align_arg_pointer)) void gaussHorizontal3Sse (T** src, T** dst, int W, int H, const float c0, const float c1) { #else template void gaussHorizontal3Sse (T** src, T** dst, int W, int H, const float c0, const float c1) { #endif - float tmp[W][4] __attribute__ ((aligned (16))); - - __m128 Tv,Tm1v,Tp1v; - __m128 c0v,c1v; - c0v = _mm_set1_ps(c0); - c1v = _mm_set1_ps(c1); + float tmp[W][4] __attribute__ ((aligned (16))); + + __m128 Tv,Tm1v,Tp1v; + __m128 c0v,c1v; + c0v = _mm_set1_ps(c0); + c1v = _mm_set1_ps(c1); #ifdef _OPENMP #pragma omp for -#endif - for (int i=0; i1) + Tm1v = _mm_set_ps( src[i][0], src[i+1][0], src[i+2][0], src[i+3][0] ); + if(W>1) Tv = _mm_set_ps( src[i][1], src[i+1][1], src[i+2][1], src[i+3][1] ); - for (int j=1; j void gaussHorizontalSse (T** src, T** dst, int W, int H, float M[2][2] = b3*(b1+b3*b2); for (int i=0; i<3; i++) for (int j=0; j<3; j++) { - M[i][j] *= (1.0+b2+(b1-b3)*b3); - M[i][j] /= (1.0+b1-b2+b3)*(1.0-b1-b2-b3); - } - float tmp[W][4] __attribute__ ((aligned (16))); - float tmpV[4] __attribute__ ((aligned (16))); - __m128 Rv; - __m128 Tv,Tm2v,Tm3v; - __m128 Bv,b1v,b2v,b3v; - __m128 temp2W,temp2Wp1; - Bv = _mm_set1_ps(B); - b1v = _mm_set1_ps(b1); - b2v = _mm_set1_ps(b2); - b3v = _mm_set1_ps(b3); + M[i][j] *= (1.0+b2+(b1-b3)*b3); + M[i][j] /= (1.0+b1-b2+b3)*(1.0-b1-b2-b3); + } + float tmp[W][4] __attribute__ ((aligned (16))); + float tmpV[4] __attribute__ ((aligned (16))); + __m128 Rv; + __m128 Tv,Tm2v,Tm3v; + __m128 Bv,b1v,b2v,b3v; + __m128 temp2W,temp2Wp1; + Bv = _mm_set1_ps(B); + b1v = _mm_set1_ps(b1); + b2v = _mm_set1_ps(b2); + b3v = _mm_set1_ps(b3); #pragma omp for - for (int i=0; i=0; j--) { - Tv = Rv; - Rv = _mm_load_ps(&tmp[j][0]) * Bv + Tv * b1v + Tm2v * b2v + Tm3v * b3v; - _mm_store_ps( &tmp[j][0], Rv ); - Tm3v = Tm2v; - Tm2v = Tv; - } - - for (int j=0; j=0; j--) { + Tv = Rv; + Rv = _mm_load_ps(&tmp[j][0]) * Bv + Tv * b1v + Tm2v * b2v + Tm3v * b3v; + _mm_store_ps( &tmp[j][0], Rv ); + Tm3v = Tm2v; + Tm2v = Tv; + } + + for (int j=0; j void gaussHorizontalSse (T** src, T** dst, int W, int H, float for (int j=W-4; j>=0; j--) tmp[j][0] = B * tmp[j][0] + b1*tmp[j+1][0] + b2*tmp[j+2][0] + b3*tmp[j+3][0]; - + for (int j=0; j void gaussHorizontal (T** src, T** dst, AlignedBufferMP &buffer, int W, int H, double sigma) { - + #ifdef __SSE__ - if(sigma < 70) { // bigger sigma only with double precision - gaussHorizontalSse (src, dst, W, H, sigma); + if(sigma < 70) { // bigger sigma only with double precision + gaussHorizontalSse (src, dst, W, H, sigma); return; - } + } #endif if (sigma<0.25) { // dont perform filtering @@ -414,9 +414,9 @@ template void gaussHorizontal (T** src, T** dst, AlignedBufferMP __attribute__((force_align_arg_pointer)) void gaussVerticalSse (T** src, T** dst, int W, int H, float sigma) { #else template void gaussVerticalSse (T** src, T** dst, int W, int H, float sigma) { @@ -467,73 +467,73 @@ template void gaussVerticalSse (T** src, T** dst, int W, int H, float s M[2][2] = b3*(b1+b3*b2); for (int i=0; i<3; i++) for (int j=0; j<3; j++) { - M[i][j] *= (1.0+b2+(b1-b3)*b3); - M[i][j] /= (1.0+b1-b2+b3)*(1.0-b1-b2-b3); - } - float tmp[H][4] __attribute__ ((aligned (16))); - __m128 Rv; - __m128 Tv,Tm2v,Tm3v; - __m128 Bv,b1v,b2v,b3v; - __m128 temp2W,temp2Wp1; - Bv = _mm_set1_ps(B); - b1v = _mm_set1_ps(b1); - b2v = _mm_set1_ps(b2); - b3v = _mm_set1_ps(b3); - - + M[i][j] *= (1.0+b2+(b1-b3)*b3); + M[i][j] /= (1.0+b1-b2+b3)*(1.0-b1-b2-b3); + } + float tmp[H][4] __attribute__ ((aligned (16))); + __m128 Rv; + __m128 Tv,Tm2v,Tm3v; + __m128 Bv,b1v,b2v,b3v; + __m128 temp2W,temp2Wp1; + Bv = _mm_set1_ps(B); + b1v = _mm_set1_ps(b1); + b2v = _mm_set1_ps(b2); + b3v = _mm_set1_ps(b3); + + #ifdef _OPENMP #pragma omp for #endif - for (int i=0; i=0; j--) { - Tv = Rv; - Rv = _mm_load_ps(&tmp[j][0]) * Bv + Tv * b1v + Tm2v * b2v + Tm3v * b3v; - _mm_storeu_ps( &dst[j][i], Rv ); - Tm3v = Tm2v; - Tm2v = Tv; - } - } -// Borders are done without SSE -#pragma omp for - for(int i=W-(W%4);i=0; j--) { + Tv = Rv; + Rv = _mm_load_ps(&tmp[j][0]) * Bv + Tv * b1v + Tm2v * b2v + Tm3v * b3v; + _mm_storeu_ps( &dst[j][i], Rv ); + Tm3v = Tm2v; + Tm2v = Tv; + } + } +// Borders are done without SSE +#pragma omp for + for(int i=W-(W%4);i void gaussVerticalSse (T** src, T** dst, int W, int H, float s for (int j=0; j void gaussVertical (T** src, T** dst, AlignedBufferMP &buffer, int W, int H, double sigma) { - + #ifdef __SSE__ - if(sigma < 70) { // bigger sigma only with double precision - gaussVerticalSse (src, dst, W, H, sigma); + if(sigma < 70) { // bigger sigma only with double precision + gaussVerticalSse (src, dst, W, H, sigma); return; - } + } #endif if (sigma<0.25) { @@ -644,7 +644,7 @@ template void gaussVertical (T** src, T** dst, AlignedBufferMP dst[j][i] = (T)temp2[j]; buffer.release(pBuf); - } + } } diff --git a/rtengine/imagedimensions.cc b/rtengine/imagedimensions.cc index f1126e155..949533245 100644 --- a/rtengine/imagedimensions.cc +++ b/rtengine/imagedimensions.cc @@ -1,63 +1,63 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include "imagedimensions.h" -#include "rtengine.h" - -void ImageDimensions::transform (PreviewProps pp, int tran, int &sx1, int &sy1, int &sx2, int &sy2) { - - int sw = width, sh = height; - if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { - sw = height; - sh = width; - } - int ppx = pp.x, ppy = pp.y; - if (tran & TR_HFLIP) - ppx = sw - pp.x - pp.w; - if (tran & TR_VFLIP) - ppy = sh - pp.y - pp.h; - - sx1 = ppx; - sy1 = ppy; - sx2 = ppx + pp.w; - sy2 = ppy + pp.h; - - if ((tran & TR_ROT) == TR_R180) { - sx1 = width - ppx - pp.w; - sy1 = height - ppy - pp.h; - sx2 = sx1 + pp.w; - sy2 = sy1 + pp.h; - } - else if ((tran & TR_ROT) == TR_R90) { - sx1 = ppy; - sy1 = height - ppx - pp.w; - sx2 = sx1 + pp.h; - sy2 = sy1 + pp.w; - } - else if ((tran & TR_ROT) == TR_R270) { - sx1 = width - ppy - pp.h; - sy1 = ppx; - sx2 = sx1 + pp.h; - sy2 = sy1 + pp.w; - } - //printf ("ppx %d ppy %d ppw %d pph %d s: %d %d %d %d\n",pp.x, pp.y,pp.w,pp.h,sx1,sy1,sx2,sy2); - if (sx1<0)sx1=0; - if (sy1<0)sy1=0; -} - +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "imagedimensions.h" +#include "rtengine.h" + +void ImageDimensions::transform (PreviewProps pp, int tran, int &sx1, int &sy1, int &sx2, int &sy2) { + + int sw = width, sh = height; + if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { + sw = height; + sh = width; + } + int ppx = pp.x, ppy = pp.y; + if (tran & TR_HFLIP) + ppx = sw - pp.x - pp.w; + if (tran & TR_VFLIP) + ppy = sh - pp.y - pp.h; + + sx1 = ppx; + sy1 = ppy; + sx2 = ppx + pp.w; + sy2 = ppy + pp.h; + + if ((tran & TR_ROT) == TR_R180) { + sx1 = width - ppx - pp.w; + sy1 = height - ppy - pp.h; + sx2 = sx1 + pp.w; + sy2 = sy1 + pp.h; + } + else if ((tran & TR_ROT) == TR_R90) { + sx1 = ppy; + sy1 = height - ppx - pp.w; + sx2 = sx1 + pp.h; + sy2 = sy1 + pp.w; + } + else if ((tran & TR_ROT) == TR_R270) { + sx1 = width - ppy - pp.h; + sy1 = ppx; + sx2 = sx1 + pp.h; + sy2 = sy1 + pp.w; + } + //printf ("ppx %d ppy %d ppw %d pph %d s: %d %d %d %d\n",pp.x, pp.y,pp.w,pp.h,sx1,sy1,sx2,sy2); + if (sx1<0)sx1=0; + if (sy1<0)sy1=0; +} + diff --git a/rtengine/imagedimensions.h b/rtengine/imagedimensions.h index 9126d500d..547c3aaf7 100644 --- a/rtengine/imagedimensions.h +++ b/rtengine/imagedimensions.h @@ -1,49 +1,49 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#ifndef _IMAGEDIMENSIONS_ -#define _IMAGEDIMENSIONS_ - -class PreviewProps { - public: - int x, y, w, h, skip; - PreviewProps (int _x, int _y, int _w, int _h, int _skip) - : x(_x), y(_y), w(_w), h(_h), skip(_skip) {} -}; - -/* - * Description of an image dimension, with getter and setter - */ -class ImageDimensions { - - public: - int width; - int height; - - public: - ImageDimensions() : width(-1), height(-1) {} - int getW () { return width; } - int getH () { return height; } - int getWidth () { return width; } - int getHeight () { return height; } - void transform (PreviewProps pp, int tran, int &sx1, int &sy1, int &sx2, int &sy2); -}; - - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#ifndef _IMAGEDIMENSIONS_ +#define _IMAGEDIMENSIONS_ + +class PreviewProps { + public: + int x, y, w, h, skip; + PreviewProps (int _x, int _y, int _w, int _h, int _skip) + : x(_x), y(_y), w(_w), h(_h), skip(_skip) {} +}; + +/* + * Description of an image dimension, with getter and setter + */ +class ImageDimensions { + + public: + int width; + int height; + + public: + ImageDimensions() : width(-1), height(-1) {} + int getW () { return width; } + int getH () { return height; } + int getWidth () { return width; } + int getHeight () { return height; } + void transform (PreviewProps pp, int tran, int &sx1, int &sy1, int &sx2, int &sy2); +}; + + +#endif diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 5c0d87f52..4b12e7856 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -1,342 +1,342 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * Copyright (c) 2010 Oliver Duis - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include -#include -#include -#include -#include -#include -#include +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2010 Oliver Duis + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include #include -#include "rt_math.h" -#include "../rtgui/options.h" -#include "../rtgui/version.h" +#include "rt_math.h" +#include "../rtgui/options.h" +#include "../rtgui/version.h" -#ifdef WIN32 -#include -#else -#include -#endif +#ifdef WIN32 +#include +#else +#include +#endif #include "imageio.h" #include "safegtk.h" -#include "iptcpairs.h" -#include "iccjpeg.h" -#include "color.h" - -#include "jpeg.h" - +#include "iptcpairs.h" +#include "iccjpeg.h" +#include "color.h" + +#include "jpeg.h" + using namespace std; -using namespace rtengine; -using namespace rtengine::procparams; - +using namespace rtengine; +using namespace rtengine::procparams; + Glib::ustring safe_locale_to_utf8 (const std::string& src); -Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.","Error while reading header.","File reading error", "Image format not supported."}; - - -// For only copying the raw input data -void ImageIO::setMetadata (const rtexif::TagDirectory* eroot) { - if (exifRoot!=NULL) { delete exifRoot; exifRoot = NULL; } - - if (eroot) { - rtexif::TagDirectory* td = ((rtexif::TagDirectory*)eroot)->clone (NULL); - - // make IPTC and XMP pass through - td->keepTag(0x83bb); // IPTC - td->keepTag(0x02bc); // XMP - - exifRoot=td; - } -} - -// For merging with RT specific data -void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::procparams::ExifPairs& exif, const rtengine::procparams::IPTCPairs& iptcc) { - - // store exif info - exifChange.clear(); - exifChange = exif; - /*unsigned int j=0; - for (rtengine::procparams::ExifPairs::const_iterator i=exif.begin(); i!=exif.end(); i++) { - exifChange.at(j).first = i->first; - exifChange.at(j).second = i->second; - j++; - }*/ - - if (exifRoot!=NULL) { delete exifRoot; exifRoot = NULL; } - - if (eroot) - exifRoot = ((rtexif::TagDirectory*)eroot)->clone (NULL); - - if (iptc!=NULL) { iptc_data_free (iptc); iptc = NULL; } - - // build iptc structures for libiptcdata - if (iptcc.empty()) - return; - - iptc = iptc_data_new (); - for (rtengine::procparams::IPTCPairs::const_iterator i=iptcc.begin(); i!=iptcc.end(); i++) { - if (i->first == "Keywords" && !(i->second.empty())) { - for (unsigned int j=0; jsecond.size(); j++) { - IptcDataSet * ds = iptc_dataset_new (); - iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS); - std::string loc = safe_locale_to_utf8(i->second.at(j)); +Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.","Error while reading header.","File reading error", "Image format not supported."}; + + +// For only copying the raw input data +void ImageIO::setMetadata (const rtexif::TagDirectory* eroot) { + if (exifRoot!=NULL) { delete exifRoot; exifRoot = NULL; } + + if (eroot) { + rtexif::TagDirectory* td = ((rtexif::TagDirectory*)eroot)->clone (NULL); + + // make IPTC and XMP pass through + td->keepTag(0x83bb); // IPTC + td->keepTag(0x02bc); // XMP + + exifRoot=td; + } +} + +// For merging with RT specific data +void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::procparams::ExifPairs& exif, const rtengine::procparams::IPTCPairs& iptcc) { + + // store exif info + exifChange.clear(); + exifChange = exif; + /*unsigned int j=0; + for (rtengine::procparams::ExifPairs::const_iterator i=exif.begin(); i!=exif.end(); i++) { + exifChange.at(j).first = i->first; + exifChange.at(j).second = i->second; + j++; + }*/ + + if (exifRoot!=NULL) { delete exifRoot; exifRoot = NULL; } + + if (eroot) + exifRoot = ((rtexif::TagDirectory*)eroot)->clone (NULL); + + if (iptc!=NULL) { iptc_data_free (iptc); iptc = NULL; } + + // build iptc structures for libiptcdata + if (iptcc.empty()) + return; + + iptc = iptc_data_new (); + for (rtengine::procparams::IPTCPairs::const_iterator i=iptcc.begin(); i!=iptcc.end(); i++) { + if (i->first == "Keywords" && !(i->second.empty())) { + for (unsigned int j=0; jsecond.size(); j++) { + IptcDataSet * ds = iptc_dataset_new (); + iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS); + std::string loc = safe_locale_to_utf8(i->second.at(j)); iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), min(static_cast(64), loc.size()), IPTC_DONT_VALIDATE); - iptc_data_add_dataset (iptc, ds); - iptc_dataset_unref (ds); - } - continue; - } - else if (i->first == "SupplementalCategories" && !(i->second.empty())) { - for (unsigned int j=0; jsecond.size(); j++) { - IptcDataSet * ds = iptc_dataset_new (); - iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY); - std::string loc = safe_locale_to_utf8(i->second.at(j)); - iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), min(static_cast(32), loc.size()), IPTC_DONT_VALIDATE); - iptc_data_add_dataset (iptc, ds); - iptc_dataset_unref (ds); - } - continue; - } - for (int j=0; j<16; j++) - if (i->first == strTags[j].field && !(i->second.empty())) { - IptcDataSet * ds = iptc_dataset_new (); - iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, strTags[j].tag); - std::string loc = safe_locale_to_utf8(i->second.at(0)); + iptc_data_add_dataset (iptc, ds); + iptc_dataset_unref (ds); + } + continue; + } + else if (i->first == "SupplementalCategories" && !(i->second.empty())) { + for (unsigned int j=0; jsecond.size(); j++) { + IptcDataSet * ds = iptc_dataset_new (); + iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY); + std::string loc = safe_locale_to_utf8(i->second.at(j)); + iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), min(static_cast(32), loc.size()), IPTC_DONT_VALIDATE); + iptc_data_add_dataset (iptc, ds); + iptc_dataset_unref (ds); + } + continue; + } + for (int j=0; j<16; j++) + if (i->first == strTags[j].field && !(i->second.empty())) { + IptcDataSet * ds = iptc_dataset_new (); + iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, strTags[j].tag); + std::string loc = safe_locale_to_utf8(i->second.at(0)); iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), min(strTags[j].size, loc.size()), IPTC_DONT_VALIDATE); - iptc_data_add_dataset (iptc, ds); - iptc_dataset_unref (ds); - } - } - iptc_data_sort (iptc); -} - -void ImageIO::setOutputProfile (char* pdata, int plen) { - - delete [] profileData; - if (pdata) { - profileData = new char [plen]; - memcpy (profileData, pdata, plen); - } - else - profileData = NULL; - profileLength = plen; -} - -ImageIO::~ImageIO () { - - if (embProfile) + iptc_data_add_dataset (iptc, ds); + iptc_dataset_unref (ds); + } + } + iptc_data_sort (iptc); +} + +void ImageIO::setOutputProfile (char* pdata, int plen) { + + delete [] profileData; + if (pdata) { + profileData = new char [plen]; + memcpy (profileData, pdata, plen); + } + else + profileData = NULL; + profileLength = plen; +} + +ImageIO::~ImageIO () { + + if (embProfile) cmsCloseProfile(embProfile); - deleteLoadedProfileData(); - delete exifRoot; - delete [] profileData; -} - -void png_read_data(png_struct_def *png_ptr, unsigned char *data, size_t length); -void png_write_data(png_struct_def *png_ptr, unsigned char *data, size_t length); -void png_flush(png_struct_def *png_ptr); - -int ImageIO::getPNGSampleFormat (Glib::ustring fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement) { - FILE *file = safe_g_fopen (fname,"rb"); - if (!file) - return IMIO_CANNOTREADFILE; - - //reading PNG header - unsigned char header[8]; - fread (header, 1, 8, file); - if (png_sig_cmp (header, 0, 8)) { - fclose(file); - return IMIO_HEADERERROR; - } - //initializing main structures - png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (!png) { - fclose (file); - return IMIO_HEADERERROR; - } - png_infop info = png_create_info_struct (png); - png_infop end_info = png_create_info_struct (png); - if (!end_info || !info) { - png_destroy_read_struct (&png, &info, &end_info); - fclose (file); - return IMIO_HEADERERROR; - } - - if (setjmp (png_jmpbuf(png))) { - png_destroy_read_struct (&png, &info, &end_info); - fclose (file); - return IMIO_READERROR; - } - - //set up png read - png_set_read_fn (png, file, png_read_data); - png_set_sig_bytes (png,8); - - png_read_info(png,info); - - //retrieving image information - png_uint_32 width,height; - int bit_depth,color_type,interlace_type,compression_type,filter_method; - png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type,&compression_type, &filter_method); - - png_destroy_read_struct (&png, &info, &end_info); - fclose (file); - - if (interlace_type!=PNG_INTERLACE_NONE) - return IMIO_VARIANTNOTSUPPORTED; - - if (bit_depth == 8) { - sArrangement = IIOSA_CHUNKY; - sFormat = IIOSF_UNSIGNED_CHAR; - return IMIO_SUCCESS; - } - else if (bit_depth == 16) { - sArrangement = IIOSA_CHUNKY; - sFormat = IIOSF_UNSIGNED_SHORT; - return IMIO_SUCCESS; - } - else { - sArrangement = IIOSA_UNKNOWN; - sFormat = IIOSF_UNKNOWN; - return IMIO_VARIANTNOTSUPPORTED; - } -} - -int ImageIO::loadPNG (Glib::ustring fname) { - - FILE *file = safe_g_fopen (fname,"rb"); - if (!file) - return IMIO_CANNOTREADFILE; - - if (pl) { - pl->setProgressStr ("PROGRESSBAR_LOADPNG"); - pl->setProgress (0.0); - } - - //reading PNG header - unsigned char header[8]; - fread (header, 1, 8, file); - if (png_sig_cmp (header, 0, 8)) { - fclose(file); - return IMIO_HEADERERROR; - } - //initializing main structures - png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (!png) { - fclose (file); - return IMIO_HEADERERROR; - } - png_infop info = png_create_info_struct (png); - png_infop end_info = png_create_info_struct (png); - if (!end_info || !info) { - png_destroy_read_struct (&png, &info, &end_info); - fclose (file); - return IMIO_HEADERERROR; - } - - if (setjmp (png_jmpbuf(png))) { - png_destroy_read_struct (&png, &info, &end_info); - fclose (file); - return IMIO_READERROR; - } - - //set up png read - png_set_read_fn (png, file, png_read_data); - png_set_sig_bytes (png,8); - - png_read_info(png,info); - - embProfile = NULL; - - //retrieving image information - png_uint_32 width,height; - int bit_depth,color_type,interlace_type,compression_type,filter_method; - png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); - + deleteLoadedProfileData(); + delete exifRoot; + delete [] profileData; +} + +void png_read_data(png_struct_def *png_ptr, unsigned char *data, size_t length); +void png_write_data(png_struct_def *png_ptr, unsigned char *data, size_t length); +void png_flush(png_struct_def *png_ptr); + +int ImageIO::getPNGSampleFormat (Glib::ustring fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement) { + FILE *file = safe_g_fopen (fname,"rb"); + if (!file) + return IMIO_CANNOTREADFILE; + + //reading PNG header + unsigned char header[8]; + fread (header, 1, 8, file); + if (png_sig_cmp (header, 0, 8)) { + fclose(file); + return IMIO_HEADERERROR; + } + //initializing main structures + png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!png) { + fclose (file); + return IMIO_HEADERERROR; + } + png_infop info = png_create_info_struct (png); + png_infop end_info = png_create_info_struct (png); + if (!end_info || !info) { + png_destroy_read_struct (&png, &info, &end_info); + fclose (file); + return IMIO_HEADERERROR; + } + + if (setjmp (png_jmpbuf(png))) { + png_destroy_read_struct (&png, &info, &end_info); + fclose (file); + return IMIO_READERROR; + } + + //set up png read + png_set_read_fn (png, file, png_read_data); + png_set_sig_bytes (png,8); + + png_read_info(png,info); + + //retrieving image information + png_uint_32 width,height; + int bit_depth,color_type,interlace_type,compression_type,filter_method; + png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type,&compression_type, &filter_method); + + png_destroy_read_struct (&png, &info, &end_info); + fclose (file); + + if (interlace_type!=PNG_INTERLACE_NONE) + return IMIO_VARIANTNOTSUPPORTED; + + if (bit_depth == 8) { + sArrangement = IIOSA_CHUNKY; + sFormat = IIOSF_UNSIGNED_CHAR; + return IMIO_SUCCESS; + } + else if (bit_depth == 16) { + sArrangement = IIOSA_CHUNKY; + sFormat = IIOSF_UNSIGNED_SHORT; + return IMIO_SUCCESS; + } + else { + sArrangement = IIOSA_UNKNOWN; + sFormat = IIOSF_UNKNOWN; + return IMIO_VARIANTNOTSUPPORTED; + } +} + +int ImageIO::loadPNG (Glib::ustring fname) { + + FILE *file = safe_g_fopen (fname,"rb"); + if (!file) + return IMIO_CANNOTREADFILE; + + if (pl) { + pl->setProgressStr ("PROGRESSBAR_LOADPNG"); + pl->setProgress (0.0); + } + + //reading PNG header + unsigned char header[8]; + fread (header, 1, 8, file); + if (png_sig_cmp (header, 0, 8)) { + fclose(file); + return IMIO_HEADERERROR; + } + //initializing main structures + png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!png) { + fclose (file); + return IMIO_HEADERERROR; + } + png_infop info = png_create_info_struct (png); + png_infop end_info = png_create_info_struct (png); + if (!end_info || !info) { + png_destroy_read_struct (&png, &info, &end_info); + fclose (file); + return IMIO_HEADERERROR; + } + + if (setjmp (png_jmpbuf(png))) { + png_destroy_read_struct (&png, &info, &end_info); + fclose (file); + return IMIO_READERROR; + } + + //set up png read + png_set_read_fn (png, file, png_read_data); + png_set_sig_bytes (png,8); + + png_read_info(png,info); + + embProfile = NULL; + + //retrieving image information + png_uint_32 width,height; + int bit_depth,color_type,interlace_type,compression_type,filter_method; + png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); + if (color_type==PNG_COLOR_TYPE_PALETTE || interlace_type!=PNG_INTERLACE_NONE ) { // we don't support interlaced png or png with palette - png_destroy_read_struct (&png, &info, &end_info); + png_destroy_read_struct (&png, &info, &end_info); fclose (file); printf("%s uses an unsupported feature: . Skipping.\n",fname.data()); - return IMIO_VARIANTNOTSUPPORTED; - } - - if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png); - + return IMIO_VARIANTNOTSUPPORTED; + } + + if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + if (png_get_valid(png,info,PNG_INFO_tRNS)) - png_set_tRNS_to_alpha(png); - - if (color_type & PNG_COLOR_MASK_ALPHA) - png_set_strip_alpha(png); - + png_set_tRNS_to_alpha(png); + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png); + //setting gamma double gamma; if (png_get_gAMA(png,info,&gamma)) png_set_gamma(png, 1.0/gamma, gamma); // use gamma from metadata else png_set_gamma(png, 2.2, 1.0/2.2); // no gamma in metadata, suppose gamma 2.2 - -// if (bps==8 && bit_depth==16) png_set_strip_16(png); - - //updating png info struct - png_read_update_info(png,info); - png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type,&compression_type, &filter_method); - - allocate (width, height); - - int rowlen = width*3*bit_depth/8; + +// if (bps==8 && bit_depth==16) png_set_strip_16(png); + + //updating png info struct + png_read_update_info(png,info); + png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type,&compression_type, &filter_method); + + allocate (width, height); + + int rowlen = width*3*bit_depth/8; unsigned char *row = new unsigned char [rowlen]; // set a new jump point to avoid memory leak - if (setjmp (png_jmpbuf(png))) { + if (setjmp (png_jmpbuf(png))) { png_destroy_read_struct (&png, &info, &end_info); fclose (file); - delete [] row; - return IMIO_READERROR; - } - - for (unsigned int i=0;isetProgress ((double)(i+1)/height); - } - - png_read_end (png, 0); - png_destroy_read_struct (&png, &info, &end_info); - - delete [] row; - fclose(file); - if (pl) { - pl->setProgressStr ("PROGRESSBAR_READY"); - pl->setProgress (1.0); - } - return IMIO_SUCCESS; -} + delete [] row; + return IMIO_READERROR; + } + + for (unsigned int i=0;isetProgress ((double)(i+1)/height); + } + + png_read_end (png, 0); + png_destroy_read_struct (&png, &info, &end_info); + + delete [] row; + fclose(file); + if (pl) { + pl->setProgressStr ("PROGRESSBAR_READY"); + pl->setProgress (1.0); + } + return IMIO_SUCCESS; +} typedef struct { struct jpeg_error_mgr pub; /* "public" fields */ @@ -358,11 +358,11 @@ void my_error_exit (j_common_ptr cinfo) { #endif } - -int ImageIO::loadJPEGFromMemory (const char* buffer, int bufsize) + +int ImageIO::loadJPEGFromMemory (const char* buffer, int bufsize) { - jpeg_decompress_struct cinfo; - jpeg_create_decompress(&cinfo); + jpeg_decompress_struct cinfo; + jpeg_create_decompress(&cinfo); jpeg_memory_src (&cinfo,(const JOCTET*)buffer,bufsize); /* We use our private extension JPEG error handler. @@ -385,499 +385,499 @@ int ImageIO::loadJPEGFromMemory (const char* buffer, int bufsize) */ jpeg_destroy_decompress(&cinfo); return IMIO_READERROR; - } + } + + + if (pl) { + pl->setProgressStr ("PROGRESSBAR_LOADJPEG"); + pl->setProgress (0.0); + + } + + setup_read_icc_profile (&cinfo); + + jpeg_read_header(&cinfo, TRUE); - - if (pl) { - pl->setProgressStr ("PROGRESSBAR_LOADJPEG"); - pl->setProgress (0.0); - - } - - setup_read_icc_profile (&cinfo); - - jpeg_read_header(&cinfo, TRUE); - deleteLoadedProfileData(); - loadedProfileDataJpg = true; - bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength); - if (hasprofile) - embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength); - else - embProfile = NULL; - - jpeg_start_decompress(&cinfo); - - unsigned int width = cinfo.output_width; - unsigned int height = cinfo.output_height; - - allocate (width, height); - - unsigned char *row=new unsigned char[width*3]; - while (cinfo.output_scanline < height) { - if (jpeg_read_scanlines(&cinfo,&row,1) < 1) { - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - delete [] row; - return IMIO_READERROR; - } - setScanline (cinfo.output_scanline-1, row, 8); - - if (pl && !(cinfo.output_scanline%100)) - pl->setProgress ((double)(cinfo.output_scanline)/cinfo.output_height); - } - delete [] row; - - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - if (pl) { - pl->setProgressStr ("PROGRESSBAR_READY"); - pl->setProgress (1.0); - } - return IMIO_SUCCESS; -} - -int ImageIO::loadJPEG (Glib::ustring fname) { - FILE *file=safe_g_fopen(fname,"rb"); - if (!file) - return IMIO_CANNOTREADFILE; - - jpeg_decompress_struct cinfo; - jpeg_error_mgr jerr; - cinfo.err = my_jpeg_std_error(&jerr); - jpeg_create_decompress(&cinfo); - - my_jpeg_stdio_src (&cinfo,file); - if ( setjmp((reinterpret_cast(cinfo.src))->error_jmp_buf) == 0 ) - { - if (pl) { - pl->setProgressStr ("PROGRESSBAR_LOADJPEG"); - pl->setProgress (0.0); - } - - setup_read_icc_profile (&cinfo); - - //jpeg_stdio_src(&cinfo,file); - jpeg_read_header(&cinfo, TRUE); - - //if JPEG is CMYK, then abort reading - if (cinfo.jpeg_color_space == JCS_CMYK || cinfo.jpeg_color_space == JCS_YCCK || cinfo.jpeg_color_space == JCS_GRAYSCALE) { - jpeg_destroy_decompress(&cinfo); - return IMIO_READERROR; - } - + loadedProfileDataJpg = true; + bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength); + if (hasprofile) + embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength); + else + embProfile = NULL; + + jpeg_start_decompress(&cinfo); + + unsigned int width = cinfo.output_width; + unsigned int height = cinfo.output_height; + + allocate (width, height); + + unsigned char *row=new unsigned char[width*3]; + while (cinfo.output_scanline < height) { + if (jpeg_read_scanlines(&cinfo,&row,1) < 1) { + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + delete [] row; + return IMIO_READERROR; + } + setScanline (cinfo.output_scanline-1, row, 8); + + if (pl && !(cinfo.output_scanline%100)) + pl->setProgress ((double)(cinfo.output_scanline)/cinfo.output_height); + } + delete [] row; + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + if (pl) { + pl->setProgressStr ("PROGRESSBAR_READY"); + pl->setProgress (1.0); + } + return IMIO_SUCCESS; +} + +int ImageIO::loadJPEG (Glib::ustring fname) { + FILE *file=safe_g_fopen(fname,"rb"); + if (!file) + return IMIO_CANNOTREADFILE; + + jpeg_decompress_struct cinfo; + jpeg_error_mgr jerr; + cinfo.err = my_jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + my_jpeg_stdio_src (&cinfo,file); + if ( setjmp((reinterpret_cast(cinfo.src))->error_jmp_buf) == 0 ) + { + if (pl) { + pl->setProgressStr ("PROGRESSBAR_LOADJPEG"); + pl->setProgress (0.0); + } + + setup_read_icc_profile (&cinfo); + + //jpeg_stdio_src(&cinfo,file); + jpeg_read_header(&cinfo, TRUE); + + //if JPEG is CMYK, then abort reading + if (cinfo.jpeg_color_space == JCS_CMYK || cinfo.jpeg_color_space == JCS_YCCK || cinfo.jpeg_color_space == JCS_GRAYSCALE) { + jpeg_destroy_decompress(&cinfo); + return IMIO_READERROR; + } + deleteLoadedProfileData(); - loadedProfileDataJpg = true; - bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength); - if (hasprofile) - embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength); - else - embProfile = NULL; - - jpeg_start_decompress(&cinfo); - - unsigned int width = cinfo.output_width; - unsigned int height = cinfo.output_height; - - allocate (width, height); - - unsigned char *row=new unsigned char[width*3]; - while (cinfo.output_scanline < height) { - if (jpeg_read_scanlines(&cinfo,&row,1) < 1) { - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - delete [] row; - return IMIO_READERROR; - } - setScanline (cinfo.output_scanline-1, row, 8); - - if (pl && !(cinfo.output_scanline%100)) - pl->setProgress ((double)(cinfo.output_scanline)/cinfo.output_height); - } - delete [] row; - - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - fclose(file); - if (pl) { - pl->setProgressStr ("PROGRESSBAR_READY"); - pl->setProgress (1.0); - } - return IMIO_SUCCESS; - } - else { - jpeg_destroy_decompress(&cinfo); - return IMIO_READERROR; - } -} - -int ImageIO::getTIFFSampleFormat (Glib::ustring fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement) { -#ifdef WIN32 - wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); - TIFF* in = TIFFOpenW (wfilename, "r"); - g_free (wfilename); -#else - TIFF* in = TIFFOpen(fname.c_str(), "r"); -#endif - if (in == NULL) - return IMIO_CANNOTREADFILE; - - uint16 bitspersample=0, samplesperpixel=0, sampleformat=0; - int hasTag = TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample); - hasTag &= TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); - if (!hasTag) { - // These are needed - TIFFClose(in); - sFormat = IIOSF_UNKNOWN; - return IMIO_VARIANTNOTSUPPORTED; - } - if (!TIFFGetField(in, TIFFTAG_SAMPLEFORMAT, &sampleformat)) - /* - * WARNING: This is a dirty hack! - * We assume that files which doesn't contain the TIFFTAG_SAMPLEFORMAT tag - * (which is the case with uncompressed TIFFs produced by RT!) are RGB files, - * but that may be not true. --- Hombre - */ - sampleformat = SAMPLEFORMAT_UINT; - - uint16 config; - TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config); - if (config == PLANARCONFIG_CONTIG) { - sArrangement = IIOSA_CHUNKY; - } - else { - sFormat = IIOSF_UNKNOWN; - sArrangement = IIOSA_UNKNOWN; - TIFFClose(in); - return IMIO_VARIANTNOTSUPPORTED; - } - - uint16 photometric; - if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric)) { - TIFFClose(in); - return IMIO_VARIANTNOTSUPPORTED; - } - - uint16 compression; - if (photometric == PHOTOMETRIC_LOGLUV) - if (!TIFFGetField(in, TIFFTAG_COMPRESSION, &compression)) - compression = COMPRESSION_NONE; - - TIFFClose(in); - - if (photometric == PHOTOMETRIC_RGB) { - if ((samplesperpixel==3 || samplesperpixel==4) && sampleformat==SAMPLEFORMAT_UINT) { - if (bitspersample==8) { - sFormat = IIOSF_UNSIGNED_CHAR; - return IMIO_SUCCESS; - } - if (bitspersample==16) { - sFormat = IIOSF_UNSIGNED_SHORT; - return IMIO_SUCCESS; - } - } - else if (samplesperpixel==3 && sampleformat==SAMPLEFORMAT_IEEEFP) { - /* - * Not yet supported - * - if (bitspersample==16) { - sFormat = IIOSF_HALF; - return IMIO_SUCCESS; - }*/ - if ((samplesperpixel==3 || samplesperpixel==4) && bitspersample==32) { - sFormat = IIOSF_FLOAT; - return IMIO_SUCCESS; - } - } - } - else if (samplesperpixel==3 && photometric == PHOTOMETRIC_LOGLUV) { - if (compression==COMPRESSION_SGILOG24) { - sFormat = IIOSF_LOGLUV24; - return IMIO_SUCCESS; - } - else if (compression==COMPRESSION_SGILOG) { - sFormat = IIOSF_LOGLUV32; - return IMIO_SUCCESS; - } - } - return IMIO_VARIANTNOTSUPPORTED; -} - -int ImageIO::loadTIFF (Glib::ustring fname) { + loadedProfileDataJpg = true; + bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength); + if (hasprofile) + embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength); + else + embProfile = NULL; + + jpeg_start_decompress(&cinfo); + + unsigned int width = cinfo.output_width; + unsigned int height = cinfo.output_height; + + allocate (width, height); + + unsigned char *row=new unsigned char[width*3]; + while (cinfo.output_scanline < height) { + if (jpeg_read_scanlines(&cinfo,&row,1) < 1) { + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + delete [] row; + return IMIO_READERROR; + } + setScanline (cinfo.output_scanline-1, row, 8); + + if (pl && !(cinfo.output_scanline%100)) + pl->setProgress ((double)(cinfo.output_scanline)/cinfo.output_height); + } + delete [] row; + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(file); + if (pl) { + pl->setProgressStr ("PROGRESSBAR_READY"); + pl->setProgress (1.0); + } + return IMIO_SUCCESS; + } + else { + jpeg_destroy_decompress(&cinfo); + return IMIO_READERROR; + } +} + +int ImageIO::getTIFFSampleFormat (Glib::ustring fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement) { +#ifdef WIN32 + wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); + TIFF* in = TIFFOpenW (wfilename, "r"); + g_free (wfilename); +#else + TIFF* in = TIFFOpen(fname.c_str(), "r"); +#endif + if (in == NULL) + return IMIO_CANNOTREADFILE; + + uint16 bitspersample=0, samplesperpixel=0, sampleformat=0; + int hasTag = TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample); + hasTag &= TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); + if (!hasTag) { + // These are needed + TIFFClose(in); + sFormat = IIOSF_UNKNOWN; + return IMIO_VARIANTNOTSUPPORTED; + } + if (!TIFFGetField(in, TIFFTAG_SAMPLEFORMAT, &sampleformat)) + /* + * WARNING: This is a dirty hack! + * We assume that files which doesn't contain the TIFFTAG_SAMPLEFORMAT tag + * (which is the case with uncompressed TIFFs produced by RT!) are RGB files, + * but that may be not true. --- Hombre + */ + sampleformat = SAMPLEFORMAT_UINT; + + uint16 config; + TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config); + if (config == PLANARCONFIG_CONTIG) { + sArrangement = IIOSA_CHUNKY; + } + else { + sFormat = IIOSF_UNKNOWN; + sArrangement = IIOSA_UNKNOWN; + TIFFClose(in); + return IMIO_VARIANTNOTSUPPORTED; + } + + uint16 photometric; + if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric)) { + TIFFClose(in); + return IMIO_VARIANTNOTSUPPORTED; + } + + uint16 compression; + if (photometric == PHOTOMETRIC_LOGLUV) + if (!TIFFGetField(in, TIFFTAG_COMPRESSION, &compression)) + compression = COMPRESSION_NONE; + + TIFFClose(in); + + if (photometric == PHOTOMETRIC_RGB) { + if ((samplesperpixel==3 || samplesperpixel==4) && sampleformat==SAMPLEFORMAT_UINT) { + if (bitspersample==8) { + sFormat = IIOSF_UNSIGNED_CHAR; + return IMIO_SUCCESS; + } + if (bitspersample==16) { + sFormat = IIOSF_UNSIGNED_SHORT; + return IMIO_SUCCESS; + } + } + else if (samplesperpixel==3 && sampleformat==SAMPLEFORMAT_IEEEFP) { + /* + * Not yet supported + * + if (bitspersample==16) { + sFormat = IIOSF_HALF; + return IMIO_SUCCESS; + }*/ + if ((samplesperpixel==3 || samplesperpixel==4) && bitspersample==32) { + sFormat = IIOSF_FLOAT; + return IMIO_SUCCESS; + } + } + } + else if (samplesperpixel==3 && photometric == PHOTOMETRIC_LOGLUV) { + if (compression==COMPRESSION_SGILOG24) { + sFormat = IIOSF_LOGLUV24; + return IMIO_SUCCESS; + } + else if (compression==COMPRESSION_SGILOG) { + sFormat = IIOSF_LOGLUV32; + return IMIO_SUCCESS; + } + } + return IMIO_VARIANTNOTSUPPORTED; +} + +int ImageIO::loadTIFF (Glib::ustring fname) { static MyMutex thumbMutex; MyMutex::MyLock lock(thumbMutex); if(!options.serializeTiffRead) lock.release(); - -#ifdef WIN32 - wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); - TIFF* in = TIFFOpenW (wfilename, "r"); - g_free (wfilename); -#else - TIFF* in = TIFFOpen(fname.c_str(), "r"); -#endif - if (in == NULL) - return IMIO_CANNOTREADFILE; - - if (pl) { - pl->setProgressStr ("PROGRESSBAR_LOADTIFF"); - pl->setProgress (0.0); - } - - int width, height; - TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width); - TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height); - - uint16 bitspersample, samplesperpixel; - int hasTag = TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample); - hasTag &= TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); - if (!hasTag) { - // These are needed - TIFFClose(in); - return IMIO_VARIANTNOTSUPPORTED; - } - - uint16 config; - TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config); - if (config != PLANARCONFIG_CONTIG) { - TIFFClose(in); - return IMIO_VARIANTNOTSUPPORTED; - } - - if (sampleFormat & (IIOSF_LOGLUV24|IIOSF_LOGLUV32)) - TIFFSetField(in, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT); - - /* - * We could use the min/max values set in TIFFTAG_SMINSAMPLEVALUE and - * TIFFTAG_SMAXSAMPLEVALUE, but for now, we normalize the image to the - * effective minimum and maximum values - * - printf("Informations de \"%s\":\n", fname.c_str()); - uint16 tiffDefaultScale, tiffBaselineExposure, tiffLinearResponseLimit; - if (TIFFGetField(in, TIFFTAG_DEFAULTSCALE, &tiffDefaultScale)) { - printf(" DefaultScale: %d\n", tiffDefaultScale); - } - else - printf(" No DefaultScale value!\n"); - if (TIFFGetField(in, TIFFTAG_BASELINEEXPOSURE, &tiffBaselineExposure)) { - printf(" BaselineExposure: %d\n", tiffBaselineExposure); - } - else - printf(" No BaselineExposure value!\n"); - if (TIFFGetField(in, TIFFTAG_LINEARRESPONSELIMIT, &tiffLinearResponseLimit)) { - printf(" LinearResponseLimit: %d\n", tiffLinearResponseLimit); - } - else - printf(" No LinearResponseLimit value!\n"); - - uint16 tiffMinValue, tiffMaxValue; - if (TIFFGetField(in, TIFFTAG_SMINSAMPLEVALUE, &tiffMinValue)) { - printf(" MinValue: %d\n", tiffMinValue); - } - else - printf(" No minimum value!\n"); - if (TIFFGetField(in, TIFFTAG_SMAXSAMPLEVALUE, &tiffMaxValue)) { - printf(" MaxValue: %d\n\n", tiffMaxValue); - } - else - printf(" No maximum value!\n\n"); - printf("\n"); - */ - - - char* profdata; - deleteLoadedProfileData(); - loadedProfileDataJpg = false; - if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &loadedProfileLength, &profdata)) { - embProfile = cmsOpenProfileFromMem (profdata, loadedProfileLength); - - // For 32 bits floating point images, gamma is forced to linear in embedded ICC profiles - if ( sampleFormat&(IIOSF_LOGLUV24|IIOSF_LOGLUV32|IIOSF_FLOAT) ) { - // Modifying the gammaTRG tags - cmsWriteTag(embProfile, cmsSigGreenTRCTag, (void*)Color::linearGammaTRC ); - cmsWriteTag(embProfile, cmsSigRedTRCTag, (void*)Color::linearGammaTRC ); - cmsWriteTag(embProfile, cmsSigBlueTRCTag, (void*)Color::linearGammaTRC ); - - // Saving the profile in the memory - cmsUInt32Number bytesNeeded = 0; - cmsSaveProfileToMem(embProfile, 0, &bytesNeeded); - if (bytesNeeded > 0) { - loadedProfileData = new char[bytesNeeded+1]; - cmsSaveProfileToMem(embProfile, loadedProfileData, &bytesNeeded); - } - loadedProfileLength = (int)bytesNeeded; - } - else { - // Saving the profile in the memory as is - loadedProfileData = new char [loadedProfileLength]; - memcpy (loadedProfileData, profdata, loadedProfileLength); - } - - } - else - embProfile = NULL; - - allocate (width, height); - - float minValue[3]={0.f, 0.f, 0.f}, maxValue[3]={0.f, 0.f, 0.f}; - unsigned char* linebuffer = new unsigned char[TIFFScanlineSize(in)]; - for (int row = 0; row < height; row++) { - if (TIFFReadScanline(in, linebuffer, row, 0) <0) { - TIFFClose(in); - delete [] linebuffer; - return IMIO_READERROR; - } - if (samplesperpixel>3) - for (int i=0; isetProgress ((double)(row+1)/height); - } - if (sampleFormat & (IIOSF_FLOAT|IIOSF_LOGLUV24|IIOSF_LOGLUV32)) { -#ifdef _DEBUG - if (options.rtSettings.verbose) - printf("Normalizing \"%s\" image \"%s\" whose mini/maxi values are:\n Red: minimum value=%0.5f / maximum value=%0.5f\n Green: minimum value=%0.5f / maximum value=%0.5f\n Blue: minimum value=%0.5f / maximum value=%0.5f\n", - getType(), fname.c_str(), - minValue[0], maxValue[0], minValue[1], - maxValue[1], minValue[2], maxValue[2] - ); -#endif - float minVal = min( min( minValue[0],minValue[1] ),minValue[2] ); - float maxVal = max( max( maxValue[0],maxValue[1] ),maxValue[2] ); - normalizeFloat(minVal, maxVal); - } - TIFFClose(in); - delete [] linebuffer; - - if (pl) { - pl->setProgressStr ("PROGRESSBAR_READY"); - pl->setProgress (1.0); - } - - return IMIO_SUCCESS; -} - -int ImageIO::loadPPMFromMemory(const char* buffer, int width, int height, bool swap, int bps) -{ - allocate (width, height); - - int line_length(width * 3 * (bps/8)); - - if ( swap && bps > 8 ) - { - char swapped[line_length]; - for ( int row = 0; row < height; ++row ) - { - ::swab(((char*)buffer) + (row * line_length),swapped,line_length); - setScanline(row,(unsigned char*)&swapped[0],bps); - } - } - else - { - for ( int row = 0; row < height; ++row ) - { - setScanline(row,((unsigned char*)buffer) + (row * line_length),bps); - } - } - - return IMIO_SUCCESS; -} - -int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) { - - FILE *file = safe_g_fopen_WriteBinLock (fname); - - if (!file) - return IMIO_CANNOTWRITEFILE; - - if (pl) { - pl->setProgressStr ("PROGRESSBAR_SAVEPNG"); - pl->setProgress (0.0); - } - - png_structp png = png_create_write_struct (PNG_LIBPNG_VER_STRING,0,0,0); - if (!png) { - fclose (file); - return IMIO_HEADERERROR; - } - png_infop info = png_create_info_struct(png); - if (!info) { - png_destroy_write_struct (&png,0); - fclose (file); - return IMIO_HEADERERROR; - } - - if (setjmp(png_jmpbuf(png))) { - png_destroy_write_struct (&png,&info); - fclose(file); - return IMIO_CANNOTWRITEFILE; - } - - png_set_write_fn (png, file, png_write_data, png_flush); - - png_set_compression_level(png,compression); - - int width = getW (); - int height = getH (); - if (bps<0) - bps = getBPS (); - - png_set_IHDR(png, info, width, height, bps, PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_BASE); - - - int rowlen = width*3*bps/8; - unsigned char *row = new unsigned char [rowlen]; - - png_write_info(png,info); - for (int i=0;isetProgress ((double)(i+1)/height); - } - - png_write_end(png,info); - png_destroy_write_struct(&png,&info); - - delete [] row; - fclose (file); - - if (pl) { - pl->setProgressStr ("PROGRESSBAR_READY"); - pl->setProgress (1.0); - } - - return IMIO_SUCCESS; -} - + if (in == NULL) + return IMIO_CANNOTREADFILE; - -// Quality 0..100, subsampling: 1=low quality, 2=medium, 3=high -int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) { + if (pl) { + pl->setProgressStr ("PROGRESSBAR_LOADTIFF"); + pl->setProgress (0.0); + } + + int width, height; + TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height); + + uint16 bitspersample, samplesperpixel; + int hasTag = TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample); + hasTag &= TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); + if (!hasTag) { + // These are needed + TIFFClose(in); + return IMIO_VARIANTNOTSUPPORTED; + } + + uint16 config; + TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config); + if (config != PLANARCONFIG_CONTIG) { + TIFFClose(in); + return IMIO_VARIANTNOTSUPPORTED; + } + + if (sampleFormat & (IIOSF_LOGLUV24|IIOSF_LOGLUV32)) + TIFFSetField(in, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT); + + /* + * We could use the min/max values set in TIFFTAG_SMINSAMPLEVALUE and + * TIFFTAG_SMAXSAMPLEVALUE, but for now, we normalize the image to the + * effective minimum and maximum values + * + printf("Informations de \"%s\":\n", fname.c_str()); + uint16 tiffDefaultScale, tiffBaselineExposure, tiffLinearResponseLimit; + if (TIFFGetField(in, TIFFTAG_DEFAULTSCALE, &tiffDefaultScale)) { + printf(" DefaultScale: %d\n", tiffDefaultScale); + } + else + printf(" No DefaultScale value!\n"); + if (TIFFGetField(in, TIFFTAG_BASELINEEXPOSURE, &tiffBaselineExposure)) { + printf(" BaselineExposure: %d\n", tiffBaselineExposure); + } + else + printf(" No BaselineExposure value!\n"); + if (TIFFGetField(in, TIFFTAG_LINEARRESPONSELIMIT, &tiffLinearResponseLimit)) { + printf(" LinearResponseLimit: %d\n", tiffLinearResponseLimit); + } + else + printf(" No LinearResponseLimit value!\n"); + + uint16 tiffMinValue, tiffMaxValue; + if (TIFFGetField(in, TIFFTAG_SMINSAMPLEVALUE, &tiffMinValue)) { + printf(" MinValue: %d\n", tiffMinValue); + } + else + printf(" No minimum value!\n"); + if (TIFFGetField(in, TIFFTAG_SMAXSAMPLEVALUE, &tiffMaxValue)) { + printf(" MaxValue: %d\n\n", tiffMaxValue); + } + else + printf(" No maximum value!\n\n"); + printf("\n"); + */ + + + char* profdata; + deleteLoadedProfileData(); + loadedProfileDataJpg = false; + if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &loadedProfileLength, &profdata)) { + embProfile = cmsOpenProfileFromMem (profdata, loadedProfileLength); + + // For 32 bits floating point images, gamma is forced to linear in embedded ICC profiles + if ( sampleFormat&(IIOSF_LOGLUV24|IIOSF_LOGLUV32|IIOSF_FLOAT) ) { + // Modifying the gammaTRG tags + cmsWriteTag(embProfile, cmsSigGreenTRCTag, (void*)Color::linearGammaTRC ); + cmsWriteTag(embProfile, cmsSigRedTRCTag, (void*)Color::linearGammaTRC ); + cmsWriteTag(embProfile, cmsSigBlueTRCTag, (void*)Color::linearGammaTRC ); + + // Saving the profile in the memory + cmsUInt32Number bytesNeeded = 0; + cmsSaveProfileToMem(embProfile, 0, &bytesNeeded); + if (bytesNeeded > 0) { + loadedProfileData = new char[bytesNeeded+1]; + cmsSaveProfileToMem(embProfile, loadedProfileData, &bytesNeeded); + } + loadedProfileLength = (int)bytesNeeded; + } + else { + // Saving the profile in the memory as is + loadedProfileData = new char [loadedProfileLength]; + memcpy (loadedProfileData, profdata, loadedProfileLength); + } + + } + else + embProfile = NULL; + + allocate (width, height); + + float minValue[3]={0.f, 0.f, 0.f}, maxValue[3]={0.f, 0.f, 0.f}; + unsigned char* linebuffer = new unsigned char[TIFFScanlineSize(in)]; + for (int row = 0; row < height; row++) { + if (TIFFReadScanline(in, linebuffer, row, 0) <0) { + TIFFClose(in); + delete [] linebuffer; + return IMIO_READERROR; + } + if (samplesperpixel>3) + for (int i=0; isetProgress ((double)(row+1)/height); + } + if (sampleFormat & (IIOSF_FLOAT|IIOSF_LOGLUV24|IIOSF_LOGLUV32)) { +#ifdef _DEBUG + if (options.rtSettings.verbose) + printf("Normalizing \"%s\" image \"%s\" whose mini/maxi values are:\n Red: minimum value=%0.5f / maximum value=%0.5f\n Green: minimum value=%0.5f / maximum value=%0.5f\n Blue: minimum value=%0.5f / maximum value=%0.5f\n", + getType(), fname.c_str(), + minValue[0], maxValue[0], minValue[1], + maxValue[1], minValue[2], maxValue[2] + ); +#endif + float minVal = min( min( minValue[0],minValue[1] ),minValue[2] ); + float maxVal = max( max( maxValue[0],maxValue[1] ),maxValue[2] ); + normalizeFloat(minVal, maxVal); + } + TIFFClose(in); + delete [] linebuffer; + + if (pl) { + pl->setProgressStr ("PROGRESSBAR_READY"); + pl->setProgress (1.0); + } + + return IMIO_SUCCESS; +} + +int ImageIO::loadPPMFromMemory(const char* buffer, int width, int height, bool swap, int bps) +{ + allocate (width, height); + + int line_length(width * 3 * (bps/8)); + + if ( swap && bps > 8 ) + { + char swapped[line_length]; + for ( int row = 0; row < height; ++row ) + { + ::swab(((char*)buffer) + (row * line_length),swapped,line_length); + setScanline(row,(unsigned char*)&swapped[0],bps); + } + } + else + { + for ( int row = 0; row < height; ++row ) + { + setScanline(row,((unsigned char*)buffer) + (row * line_length),bps); + } + } + + return IMIO_SUCCESS; +} + +int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) { + + FILE *file = safe_g_fopen_WriteBinLock (fname); + + if (!file) + return IMIO_CANNOTWRITEFILE; + + if (pl) { + pl->setProgressStr ("PROGRESSBAR_SAVEPNG"); + pl->setProgress (0.0); + } + + png_structp png = png_create_write_struct (PNG_LIBPNG_VER_STRING,0,0,0); + if (!png) { + fclose (file); + return IMIO_HEADERERROR; + } + png_infop info = png_create_info_struct(png); + if (!info) { + png_destroy_write_struct (&png,0); + fclose (file); + return IMIO_HEADERERROR; + } + + if (setjmp(png_jmpbuf(png))) { + png_destroy_write_struct (&png,&info); + fclose(file); + return IMIO_CANNOTWRITEFILE; + } + + png_set_write_fn (png, file, png_write_data, png_flush); + + png_set_compression_level(png,compression); + + int width = getW (); + int height = getH (); + if (bps<0) + bps = getBPS (); + + png_set_IHDR(png, info, width, height, bps, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_BASE); + + + int rowlen = width*3*bps/8; + unsigned char *row = new unsigned char [rowlen]; + + png_write_info(png,info); + for (int i=0;isetProgress ((double)(i+1)/height); + } + + png_write_end(png,info); + png_destroy_write_struct(&png,&info); + + delete [] row; + fclose (file); + + if (pl) { + pl->setProgressStr ("PROGRESSBAR_READY"); + pl->setProgress (1.0); + } + + return IMIO_SUCCESS; +} + + + +// Quality 0..100, subsampling: 1=low quality, 2=medium, 3=high +int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) { + + FILE *file = safe_g_fopen_WriteBinLock (fname); + if (!file) + return IMIO_CANNOTWRITEFILE; - FILE *file = safe_g_fopen_WriteBinLock (fname); - if (!file) - return IMIO_CANNOTWRITEFILE; - jpeg_compress_struct cinfo; /* We use our private extension JPEG error handler. Note that this struct must live as long as the main JPEG parameter @@ -901,91 +901,91 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) { fclose(file); safe_g_remove(fname); return IMIO_CANNOTWRITEFILE; - } + } - jpeg_create_compress (&cinfo); - - - - if (pl) { - pl->setProgressStr ("PROGRESSBAR_SAVEJPEG"); - pl->setProgress (0.0); - } - - jpeg_stdio_dest (&cinfo, file); - - int width = getW (); - int height = getH (); - - cinfo.image_width = width; - cinfo.image_height = height; - cinfo.in_color_space = JCS_RGB; - cinfo.input_components = 3; - jpeg_set_defaults (&cinfo); - cinfo.write_JFIF_header = FALSE; - - // compute optimal Huffman coding tables for the image. Bit slower to generate, but size of result image is a bit less (default was FALSE) - cinfo.optimize_coding = TRUE; - - // Since math coprocessors are common these days, FLOAT should be a bit more accurate AND fast (default is ISLOW) - // (machine dependency is not really an issue, since we all run on x86 and having exactly the same file is not a requirement) - cinfo.dct_method = JDCT_FLOAT; - - if (quality>=0 && quality<=100) - jpeg_set_quality (&cinfo, quality, true); - - cinfo.comp_info[1].h_samp_factor=cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor=cinfo.comp_info[2].v_samp_factor = 1; - - if (subSamp==1) { - // Best compression, default of the JPEG library: 2x2, 1x1, 1x1 (4:1:1) - cinfo.comp_info[0].h_samp_factor=cinfo.comp_info[0].v_samp_factor = 2; - } else if (subSamp==2) { - // Widely used normal ratio 2x1, 1x1, 1x1 (4:2:2) - cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1; - } else if (subSamp==3) { - // Best quality 1x1 1x1 1x1 (4:4:4) - cinfo.comp_info[0].h_samp_factor=cinfo.comp_info[0].v_samp_factor = 1; - } - - jpeg_start_compress(&cinfo, TRUE); - - // buffer for exif and iptc markers - unsigned char* buffer = new unsigned char[165535]; //FIXME: no buffer size check so it can be overflowed in createJPEGMarker() for large tags, and then software will crash - unsigned int size; - // assemble and write exif marker - if (exifRoot) { - int size = rtexif::ExifManager::createJPEGMarker (exifRoot, exifChange, cinfo.image_width, cinfo.image_height, buffer); - if (size>0 && size<65530) - jpeg_write_marker(&cinfo, JPEG_APP0+1, buffer, size); - } - // assemble and write iptc marker - if (iptc) { - unsigned char* iptcdata; - bool error = false; - if (iptc_data_save (iptc, &iptcdata, &size)) { - if (iptcdata) - iptc_data_free_buf (iptc, iptcdata); - error = true; - } - int bytes = 0; - if (!error && (bytes = iptc_jpeg_ps3_save_iptc (NULL, 0, iptcdata, size, buffer, 65532)) < 0) { - if (iptcdata) - iptc_data_free_buf (iptc, iptcdata); - error = true; - } - if (!error) - jpeg_write_marker(&cinfo, JPEG_APP0+13, buffer, bytes); + jpeg_create_compress (&cinfo); + + + + if (pl) { + pl->setProgressStr ("PROGRESSBAR_SAVEJPEG"); + pl->setProgress (0.0); } - delete [] buffer; - - // write icc profile to the output - if (profileData) - write_icc_profile (&cinfo, (JOCTET*)profileData, profileLength); - - // write image data - int rowlen = width*3; - unsigned char *row = new unsigned char [rowlen]; + + jpeg_stdio_dest (&cinfo, file); + + int width = getW (); + int height = getH (); + + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; + jpeg_set_defaults (&cinfo); + cinfo.write_JFIF_header = FALSE; + + // compute optimal Huffman coding tables for the image. Bit slower to generate, but size of result image is a bit less (default was FALSE) + cinfo.optimize_coding = TRUE; + + // Since math coprocessors are common these days, FLOAT should be a bit more accurate AND fast (default is ISLOW) + // (machine dependency is not really an issue, since we all run on x86 and having exactly the same file is not a requirement) + cinfo.dct_method = JDCT_FLOAT; + + if (quality>=0 && quality<=100) + jpeg_set_quality (&cinfo, quality, true); + + cinfo.comp_info[1].h_samp_factor=cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor=cinfo.comp_info[2].v_samp_factor = 1; + + if (subSamp==1) { + // Best compression, default of the JPEG library: 2x2, 1x1, 1x1 (4:1:1) + cinfo.comp_info[0].h_samp_factor=cinfo.comp_info[0].v_samp_factor = 2; + } else if (subSamp==2) { + // Widely used normal ratio 2x1, 1x1, 1x1 (4:2:2) + cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1; + } else if (subSamp==3) { + // Best quality 1x1 1x1 1x1 (4:4:4) + cinfo.comp_info[0].h_samp_factor=cinfo.comp_info[0].v_samp_factor = 1; + } + + jpeg_start_compress(&cinfo, TRUE); + + // buffer for exif and iptc markers + unsigned char* buffer = new unsigned char[165535]; //FIXME: no buffer size check so it can be overflowed in createJPEGMarker() for large tags, and then software will crash + unsigned int size; + // assemble and write exif marker + if (exifRoot) { + int size = rtexif::ExifManager::createJPEGMarker (exifRoot, exifChange, cinfo.image_width, cinfo.image_height, buffer); + if (size>0 && size<65530) + jpeg_write_marker(&cinfo, JPEG_APP0+1, buffer, size); + } + // assemble and write iptc marker + if (iptc) { + unsigned char* iptcdata; + bool error = false; + if (iptc_data_save (iptc, &iptcdata, &size)) { + if (iptcdata) + iptc_data_free_buf (iptc, iptcdata); + error = true; + } + int bytes = 0; + if (!error && (bytes = iptc_jpeg_ps3_save_iptc (NULL, 0, iptcdata, size, buffer, 65532)) < 0) { + if (iptcdata) + iptc_data_free_buf (iptc, iptcdata); + error = true; + } + if (!error) + jpeg_write_marker(&cinfo, JPEG_APP0+13, buffer, bytes); + } + delete [] buffer; + + // write icc profile to the output + if (profileData) + write_icc_profile (&cinfo, (JOCTET*)profileData, profileLength); + + // write image data + int rowlen = width*3; + unsigned char *row = new unsigned char [rowlen]; /* To avoid memory leaks we establish a new setjmp return context for my_error_exit to use. */ #if defined( WIN32 ) && defined( __x86_64__ ) @@ -1001,269 +1001,269 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) { fclose(file); safe_g_remove(fname); return IMIO_CANNOTWRITEFILE; - } - - while (cinfo.next_scanline < cinfo.image_height) { - - getScanline (cinfo.next_scanline, row, 8); - if (jpeg_write_scanlines (&cinfo, &row, 1) < 1) { + } + + while (cinfo.next_scanline < cinfo.image_height) { + + getScanline (cinfo.next_scanline, row, 8); + if (jpeg_write_scanlines (&cinfo, &row, 1) < 1) { jpeg_destroy_compress (&cinfo); delete [] row; fclose (file); safe_g_remove(fname); - return IMIO_CANNOTWRITEFILE; - } - - if (pl && !(cinfo.next_scanline%100)) - pl->setProgress ((double)(cinfo.next_scanline)/cinfo.image_height); - } - + return IMIO_CANNOTWRITEFILE; + } + + if (pl && !(cinfo.next_scanline%100)) + pl->setProgress ((double)(cinfo.next_scanline)/cinfo.image_height); + } + jpeg_finish_compress (&cinfo); - jpeg_destroy_compress (&cinfo); - - delete [] row; - - fclose (file); - if (pl) { - pl->setProgressStr ("PROGRESSBAR_READY"); - pl->setProgress (1.0); - } - - return IMIO_SUCCESS; -} - -int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) { - - //TODO: Handling 32 bits floating point output images! + jpeg_destroy_compress (&cinfo); + + delete [] row; + + fclose (file); + if (pl) { + pl->setProgressStr ("PROGRESSBAR_READY"); + pl->setProgress (1.0); + } + + return IMIO_SUCCESS; +} + +int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) { + + //TODO: Handling 32 bits floating point output images! bool writeOk = true; - int width = getW (); - int height = getH (); - - if (bps<0) - bps = getBPS (); - - int lineWidth = width*3*bps/8; - unsigned char* linebuffer = new unsigned char[lineWidth]; -// TODO the following needs to be looked into - do we really need two ways to write a Tiff file ? - if (exifRoot && uncompressed) { - FILE *file = safe_g_fopen_WriteBinLock (fname); - - if (!file) { - delete [] linebuffer; - return IMIO_CANNOTWRITEFILE; - } - - if (pl) { - pl->setProgressStr ("PROGRESSBAR_SAVETIFF"); - pl->setProgress (0.0); - } - - // buffer for the exif and iptc - unsigned char* buffer = new unsigned char[165535]; //TODO: Is it really 165535... or 65535 ? - unsigned char* iptcdata = NULL; - unsigned int iptclen = 0; - if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen) && iptcdata) { - iptc_data_free_buf (iptc, iptcdata); - iptcdata = NULL; - } - int size = rtexif::ExifManager::createTIFFHeader (exifRoot, exifChange, width, height, bps, profileData, profileLength, (char*)iptcdata, iptclen, buffer); - if (iptcdata) - iptc_data_free_buf (iptc, iptcdata); - - // The maximum lenght is strangely not the same than for the JPEG file... - // Which maximum length is the good one ? - if (size>0 && size<165530) - fwrite (buffer, size, 1, file); - + int width = getW (); + int height = getH (); + + if (bps<0) + bps = getBPS (); + + int lineWidth = width*3*bps/8; + unsigned char* linebuffer = new unsigned char[lineWidth]; +// TODO the following needs to be looked into - do we really need two ways to write a Tiff file ? + if (exifRoot && uncompressed) { + FILE *file = safe_g_fopen_WriteBinLock (fname); + + if (!file) { + delete [] linebuffer; + return IMIO_CANNOTWRITEFILE; + } + + if (pl) { + pl->setProgressStr ("PROGRESSBAR_SAVETIFF"); + pl->setProgress (0.0); + } + + // buffer for the exif and iptc + unsigned char* buffer = new unsigned char[165535]; //TODO: Is it really 165535... or 65535 ? + unsigned char* iptcdata = NULL; + unsigned int iptclen = 0; + if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen) && iptcdata) { + iptc_data_free_buf (iptc, iptcdata); + iptcdata = NULL; + } + int size = rtexif::ExifManager::createTIFFHeader (exifRoot, exifChange, width, height, bps, profileData, profileLength, (char*)iptcdata, iptclen, buffer); + if (iptcdata) + iptc_data_free_buf (iptc, iptcdata); + + // The maximum lenght is strangely not the same than for the JPEG file... + // Which maximum length is the good one ? + if (size>0 && size<165530) + fwrite (buffer, size, 1, file); + #if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - bool needsReverse = bps==16 && exifRoot->getOrder()==rtexif::MOTOROLA; + bool needsReverse = bps==16 && exifRoot->getOrder()==rtexif::MOTOROLA; #else - bool needsReverse = bps==16 && exifRoot->getOrder()==rtexif::INTEL; + bool needsReverse = bps==16 && exifRoot->getOrder()==rtexif::INTEL; #endif - - for (int i=0; isetProgress ((double)(i+1)/height); - } - delete [] buffer; + + for (int i=0; isetProgress ((double)(i+1)/height); + } + delete [] buffer; if (ferror(file)) writeOk = false; - - fclose (file); - } - else { - // little hack to get libTiff to use proper byte order (see TIFFClienOpen()): - const char *mode = !exifRoot ? "w" : (exifRoot->getOrder()==rtexif::INTEL ? "wl":"wb"); - #ifdef WIN32 - wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); - TIFF* out = TIFFOpenW (wfilename, mode); - g_free (wfilename); - #else - TIFF* out = TIFFOpen(fname.c_str(), mode); - #endif - if (!out) { - delete [] linebuffer; - return IMIO_CANNOTWRITEFILE; - } - - if (pl) { - pl->setProgressStr ("PROGRESSBAR_SAVETIFF"); - pl->setProgress (0.0); - } - - if (exifRoot){ - rtexif::Tag *tag = exifRoot->getTag (TIFFTAG_EXIFIFD); - if (tag && tag->isDirectory()){ - rtexif::TagDirectory *exif = tag->getDirectory(); - if (exif) { - int exif_size = exif->calculateSize(); - unsigned char *buffer = new unsigned char[exif_size+8]; - // TIFFOpen writes out the header and sets file pointer at position 8 - - exif->write (8, buffer); - write (TIFFFileno (out), buffer+8, exif_size); - delete [] buffer; - // let libtiff know that scanlines or any other following stuff should go - // at a different offset: - TIFFSetWriteOffset (out, exif_size+8); - TIFFSetField (out, TIFFTAG_EXIFIFD, 8); - } - } - -//TODO Even though we are saving EXIF IFD - MakerNote still comes out screwed. - - if ((tag = exifRoot->getTag (TIFFTAG_MODEL)) != NULL) - TIFFSetField (out, TIFFTAG_MODEL, tag->getValue()); - if ((tag = exifRoot->getTag (TIFFTAG_MAKE)) != NULL) - TIFFSetField (out, TIFFTAG_MAKE, tag->getValue()); - if ((tag = exifRoot->getTag (TIFFTAG_DATETIME)) != NULL) - TIFFSetField (out, TIFFTAG_DATETIME, tag->getValue()); - if ((tag = exifRoot->getTag (TIFFTAG_ARTIST)) != NULL) - TIFFSetField (out, TIFFTAG_ARTIST, tag->getValue()); - if ((tag = exifRoot->getTag (TIFFTAG_COPYRIGHT)) != NULL) - TIFFSetField (out, TIFFTAG_COPYRIGHT, tag->getValue()); - - } - - Glib::ustring rtVersion("RawTherapee "); - rtVersion += VERSION; - TIFFSetField (out, TIFFTAG_SOFTWARE, rtVersion.c_str()); - TIFFSetField (out, TIFFTAG_IMAGEWIDTH, width); - TIFFSetField (out, TIFFTAG_IMAGELENGTH, height); - TIFFSetField (out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField (out, TIFFTAG_SAMPLESPERPIXEL, 3); - TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, height); - TIFFSetField (out, TIFFTAG_BITSPERSAMPLE, bps); - TIFFSetField (out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); - TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); - TIFFSetField (out, TIFFTAG_COMPRESSION, uncompressed ? COMPRESSION_NONE : COMPRESSION_DEFLATE); - if (!uncompressed) - TIFFSetField (out, TIFFTAG_PREDICTOR, PREDICTOR_NONE); - - if (profileData) - TIFFSetField (out, TIFFTAG_ICCPROFILE, profileLength, profileData); - - for (int row = 0; row < height; row++) { - getScanline (row, linebuffer, bps); - - if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) { - TIFFClose (out); - delete [] linebuffer; - return IMIO_CANNOTWRITEFILE; - } - if (pl && !(row%100)) - pl->setProgress ((double)(row+1)/height); + + fclose (file); + } + else { + // little hack to get libTiff to use proper byte order (see TIFFClienOpen()): + const char *mode = !exifRoot ? "w" : (exifRoot->getOrder()==rtexif::INTEL ? "wl":"wb"); + #ifdef WIN32 + wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); + TIFF* out = TIFFOpenW (wfilename, mode); + g_free (wfilename); + #else + TIFF* out = TIFFOpen(fname.c_str(), mode); + #endif + if (!out) { + delete [] linebuffer; + return IMIO_CANNOTWRITEFILE; + } + + if (pl) { + pl->setProgressStr ("PROGRESSBAR_SAVETIFF"); + pl->setProgress (0.0); + } + + if (exifRoot){ + rtexif::Tag *tag = exifRoot->getTag (TIFFTAG_EXIFIFD); + if (tag && tag->isDirectory()){ + rtexif::TagDirectory *exif = tag->getDirectory(); + if (exif) { + int exif_size = exif->calculateSize(); + unsigned char *buffer = new unsigned char[exif_size+8]; + // TIFFOpen writes out the header and sets file pointer at position 8 + + exif->write (8, buffer); + write (TIFFFileno (out), buffer+8, exif_size); + delete [] buffer; + // let libtiff know that scanlines or any other following stuff should go + // at a different offset: + TIFFSetWriteOffset (out, exif_size+8); + TIFFSetField (out, TIFFTAG_EXIFIFD, 8); + } + } + +//TODO Even though we are saving EXIF IFD - MakerNote still comes out screwed. + + if ((tag = exifRoot->getTag (TIFFTAG_MODEL)) != NULL) + TIFFSetField (out, TIFFTAG_MODEL, tag->getValue()); + if ((tag = exifRoot->getTag (TIFFTAG_MAKE)) != NULL) + TIFFSetField (out, TIFFTAG_MAKE, tag->getValue()); + if ((tag = exifRoot->getTag (TIFFTAG_DATETIME)) != NULL) + TIFFSetField (out, TIFFTAG_DATETIME, tag->getValue()); + if ((tag = exifRoot->getTag (TIFFTAG_ARTIST)) != NULL) + TIFFSetField (out, TIFFTAG_ARTIST, tag->getValue()); + if ((tag = exifRoot->getTag (TIFFTAG_COPYRIGHT)) != NULL) + TIFFSetField (out, TIFFTAG_COPYRIGHT, tag->getValue()); + + } + + Glib::ustring rtVersion("RawTherapee "); + rtVersion += VERSION; + TIFFSetField (out, TIFFTAG_SOFTWARE, rtVersion.c_str()); + TIFFSetField (out, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField (out, TIFFTAG_IMAGELENGTH, height); + TIFFSetField (out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField (out, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, height); + TIFFSetField (out, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField (out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField (out, TIFFTAG_COMPRESSION, uncompressed ? COMPRESSION_NONE : COMPRESSION_DEFLATE); + if (!uncompressed) + TIFFSetField (out, TIFFTAG_PREDICTOR, PREDICTOR_NONE); + + if (profileData) + TIFFSetField (out, TIFFTAG_ICCPROFILE, profileLength, profileData); + + for (int row = 0; row < height; row++) { + getScanline (row, linebuffer, bps); + + if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) { + TIFFClose (out); + delete [] linebuffer; + return IMIO_CANNOTWRITEFILE; + } + if (pl && !(row%100)) + pl->setProgress ((double)(row+1)/height); } if (TIFFFlush(out)!=1) writeOk = false; - - TIFFClose (out); - } - - delete [] linebuffer; - if (pl) { - pl->setProgressStr ("PROGRESSBAR_READY"); - pl->setProgress (1.0); - } - + + TIFFClose (out); + } + + delete [] linebuffer; + if (pl) { + pl->setProgressStr ("PROGRESSBAR_READY"); + pl->setProgress (1.0); + } + if(writeOk) return IMIO_SUCCESS; else { safe_g_remove(fname); return IMIO_CANNOTWRITEFILE; } -} - -// PNG read and write routines: - -void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { - png_size_t check; - - /* fread() returns 0 on error, so it is OK to store this in a png_size_t - * instead of an int, which is what fread() actually returns. - */ - check = (png_size_t)fread(data, (png_size_t)1, length, (FILE *)png_get_io_ptr(png_ptr)); - - if (check != length) - { - png_error(png_ptr, "Read Error"); - } -} - -void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { - png_uint_32 check; - - check = fwrite(data, 1, length, (FILE *)png_get_io_ptr(png_ptr)); - if (check != length) - { - png_error(png_ptr, "Write Error"); - } -} - -void png_flush(png_structp png_ptr) { - FILE *io_ptr; - io_ptr = (FILE *)(png_get_io_ptr(png_ptr)); - if (io_ptr != NULL) - fflush(io_ptr); -} - -int ImageIO::load (Glib::ustring fname) { - - size_t lastdot = fname.find_last_of ('.'); - if( Glib::ustring::npos == lastdot ) - return IMIO_FILETYPENOTSUPPORTED; - if (!fname.casefold().compare (lastdot, 4, ".png")) - return loadPNG (fname); - else if (!fname.casefold().compare (lastdot, 4, ".jpg") || - !fname.casefold().compare (lastdot, 5, ".jpeg")) - return loadJPEG (fname); - else if (!fname.casefold().compare (lastdot, 4, ".tif") || - !fname.casefold().compare (lastdot, 5, ".tiff")) - return loadTIFF (fname); - else return IMIO_FILETYPENOTSUPPORTED; -} - -int ImageIO::save (Glib::ustring fname) { - - size_t lastdot = fname.find_last_of ('.'); - if( Glib::ustring::npos == lastdot ) - return IMIO_FILETYPENOTSUPPORTED; - if (!fname.casefold().compare (lastdot, 4, ".png")) - return savePNG (fname); - else if (!fname.casefold().compare (lastdot, 4, ".jpg") || - !fname.casefold().compare (lastdot, 5, ".jpeg")) - return saveJPEG (fname); - else if (!fname.casefold().compare (lastdot, 4, ".tif") || - !fname.casefold().compare (lastdot, 5, ".tiff")) - return saveTIFF (fname); - else return IMIO_FILETYPENOTSUPPORTED; -} +} + +// PNG read and write routines: + +void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { + png_size_t check; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + check = (png_size_t)fread(data, (png_size_t)1, length, (FILE *)png_get_io_ptr(png_ptr)); + + if (check != length) + { + png_error(png_ptr, "Read Error"); + } +} + +void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { + png_uint_32 check; + + check = fwrite(data, 1, length, (FILE *)png_get_io_ptr(png_ptr)); + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} + +void png_flush(png_structp png_ptr) { + FILE *io_ptr; + io_ptr = (FILE *)(png_get_io_ptr(png_ptr)); + if (io_ptr != NULL) + fflush(io_ptr); +} + +int ImageIO::load (Glib::ustring fname) { + + size_t lastdot = fname.find_last_of ('.'); + if( Glib::ustring::npos == lastdot ) + return IMIO_FILETYPENOTSUPPORTED; + if (!fname.casefold().compare (lastdot, 4, ".png")) + return loadPNG (fname); + else if (!fname.casefold().compare (lastdot, 4, ".jpg") || + !fname.casefold().compare (lastdot, 5, ".jpeg")) + return loadJPEG (fname); + else if (!fname.casefold().compare (lastdot, 4, ".tif") || + !fname.casefold().compare (lastdot, 5, ".tiff")) + return loadTIFF (fname); + else return IMIO_FILETYPENOTSUPPORTED; +} + +int ImageIO::save (Glib::ustring fname) { + + size_t lastdot = fname.find_last_of ('.'); + if( Glib::ustring::npos == lastdot ) + return IMIO_FILETYPENOTSUPPORTED; + if (!fname.casefold().compare (lastdot, 4, ".png")) + return savePNG (fname); + else if (!fname.casefold().compare (lastdot, 4, ".jpg") || + !fname.casefold().compare (lastdot, 5, ".jpeg")) + return saveJPEG (fname); + else if (!fname.casefold().compare (lastdot, 4, ".tif") || + !fname.casefold().compare (lastdot, 5, ".tiff")) + return saveTIFF (fname); + else return IMIO_FILETYPENOTSUPPORTED; +} diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index 94d0f15d5..db33d634c 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -1,221 +1,221 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * Copyright (c) 2011 Jacques Desmis - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include "rt_math.h" -//#include - -#include "rtengine.h" -#include "improcfun.h" -#include "iccstore.h" -#include "mytime.h" -#include "../rtgui/thresholdselector.h" -#include "curves.h" +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2011 Jacques Desmis + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "rt_math.h" +//#include + +#include "rtengine.h" +#include "improcfun.h" +#include "iccstore.h" +#include "mytime.h" +#include "../rtgui/thresholdselector.h" +#include "curves.h" #include "color.h" - -#ifdef _OPENMP -#include -#endif - -using namespace std; - -namespace rtengine { - -using namespace procparams; - + +#ifdef _OPENMP +#include +#endif + +using namespace std; + +namespace rtengine { + +using namespace procparams; + #define SAT(a,b,c) ((float)max(a,b,c)-(float)min(a,b,c))/(float)max(a,b,c) - -extern const Settings* settings; - + +extern const Settings* settings; + void fillCurveArrayVib(DiagonalCurve* diagCurve, LUTf &outCurve) { - + if (diagCurve) { -#ifdef _OPENMP +#ifdef _OPENMP #pragma omp parallel for #endif - for (int i=0; i<=0xffff; i++ ) { - // change to [0,1] range - // apply custom/parametric/NURBS curve, if any - // and store result in a temporary array - outCurve[i] = 65535.f*diagCurve->getVal( double(i)/65535.0 ); + for (int i=0; i<=0xffff; i++ ) { + // change to [0,1] range + // apply custom/parametric/NURBS curve, if any + // and store result in a temporary array + outCurve[i] = 65535.f*diagCurve->getVal( double(i)/65535.0 ); } - } - else { - for (int i=0; i<=0xffff; i++) { - outCurve[i] = float(i); - } } -} - - -/* - * Vibrance correction - * copyright (c)2011 Jacques Desmis and Jean-Christophe Frisch - * - */ -void ImProcFunctions::vibrance (LabImage* lab) { + else { + for (int i=0; i<=0xffff; i++) { + outCurve[i] = float(i); + } + } +} + + +/* + * Vibrance correction + * copyright (c)2011 Jacques Desmis and Jean-Christophe Frisch + * + */ +void ImProcFunctions::vibrance (LabImage* lab) { if (!params->vibrance.enabled) - return; + return; -// int skip=1; //scale==1 ? 1 : 16; - bool skinCurveIsSet=false; - DiagonalCurve* dcurve = NULL; - dcurve = new DiagonalCurve (params->vibrance.skintonescurve, CURVES_MIN_POLY_POINTS); - if (dcurve) { - if (!dcurve->isIdentity()) { - skinCurveIsSet = true; - } - else { - delete dcurve; - dcurve = NULL; - } - } - - if (!skinCurveIsSet && !params->vibrance.pastels && !params->vibrance.saturated) { - if (dcurve) { - delete dcurve; - dcurve = NULL; +// int skip=1; //scale==1 ? 1 : 16; + bool skinCurveIsSet=false; + DiagonalCurve* dcurve = NULL; + dcurve = new DiagonalCurve (params->vibrance.skintonescurve, CURVES_MIN_POLY_POINTS); + if (dcurve) { + if (!dcurve->isIdentity()) { + skinCurveIsSet = true; + } + else { + delete dcurve; + dcurve = NULL; } - return; - } - - const int width = lab->W; - const int height = lab->H; - -#ifdef _DEBUG - MyTime t1e,t2e; - t1e.set(); - int negat=0, moreRGB=0, negsat=0, moresat=0; -#endif - - // skin hue curve - // I use diagonal because I think it's better - LUTf skin_curve (65536,0); - if(skinCurveIsSet) - fillCurveArrayVib(dcurve, skin_curve); - if (dcurve) { - delete dcurve; - dcurve = NULL; - } - - -// skin_curve.dump("skin_curve"); - - const float chromaPastel = float(params->vibrance.pastels) / 100.0f; - const float chromaSatur = float(params->vibrance.saturated) / 100.0f; - const float p00=0.07f; - const float limitpastelsatur = (static_cast(params->vibrance.psthreshold.value[ThresholdSelector::TS_TOPLEFT]) / 100.0f)*(1.0f-p00) + p00; - const float maxdp=(limitpastelsatur-p00)/4.0f; - const float maxds=(1.0-limitpastelsatur)/4.0f; - const float p0 = p00+maxdp; - const float p1 = p00+2.0f*maxdp; - const float p2 = p00+3.0f*maxdp; - const float s0 = limitpastelsatur + maxds; - const float s1 = limitpastelsatur + 2.0f*maxds; - const float s2 = limitpastelsatur + 3.0f*maxds; - const float transitionweighting = static_cast(params->vibrance.psthreshold.value[ThresholdSelector::TS_BOTTOMLEFT]) / 100.0f; - float chromamean=0.0f; - if(chromaPastel != chromaSatur){ - //if sliders pastels and saturated are different: transition with a double linear interpolation: between p2 and limitpastelsatur, and between limitpastelsatur and s0 - //modify the "mean" point in function of double threshold => differential transition - chromamean = maxdp * (chromaSatur-chromaPastel) / (s0-p2) + chromaPastel; - // move chromaMean up or down depending on transitionCtrl - if (transitionweighting > 0.0f) { - chromamean = (chromaSatur-chromamean) * transitionweighting + chromamean; - } - else if (transitionweighting < 0.0f) { - chromamean = (chromamean-chromaPastel) * transitionweighting + chromamean; - } } - const float chromaPastel_a = (chromaPastel-chromamean)/(p2-limitpastelsatur); - const float chromaPastel_b = chromaPastel-chromaPastel_a*p2; - - const float chromaSatur_a=(chromaSatur-chromamean)/(s0-limitpastelsatur); - const float chromaSatur_b=chromaSatur-chromaSatur_a*s0; - const float dhue=0.15f;//hue transition - const float dchr=20.0f;//chroma transition - const float skbeg=-0.05f;//begin hue skin - const float skend=1.60f;//end hue skin - const float xx=0.5f;//soft : between 0.3 and 1.0 - const float ask=65535.0f/(skend-skbeg); - const float bsk=-skbeg*ask; + if (!skinCurveIsSet && !params->vibrance.pastels && !params->vibrance.saturated) { + if (dcurve) { + delete dcurve; + dcurve = NULL; + } + return; + } - - const bool highlight = params->toneCurve.hrenabled;//Get the value if "highlight reconstruction" is activated - const bool protectskins = params->vibrance.protectskins; - const bool avoidcolorshift = params->vibrance.avoidcolorshift; + const int width = lab->W; + const int height = lab->H; - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); - //inverse matrix user select - const double wip[3][3] = { - {wiprof[0][0],wiprof[0][1],wiprof[0][2]}, - {wiprof[1][0],wiprof[1][1],wiprof[1][2]}, - {wiprof[2][0],wiprof[2][1],wiprof[2][2]} - }; - - -#ifdef _DEBUG - MunsellDebugInfo* MunsDebugInfo = NULL; - if (avoidcolorshift) - MunsDebugInfo = new MunsellDebugInfo(); -#pragma omp parallel default(shared) firstprivate(lab, width, height, chromaPastel, chromaSatur, highlight, limitpastelsatur, transitionweighting, protectskins, avoidcolorshift, MunsDebugInfo) reduction(+: negat, moreRGB, negsat, moresat) if (multiThread) -#else +#ifdef _DEBUG + MyTime t1e,t2e; + t1e.set(); + int negat=0, moreRGB=0, negsat=0, moresat=0; +#endif + + // skin hue curve + // I use diagonal because I think it's better + LUTf skin_curve (65536,0); + if(skinCurveIsSet) + fillCurveArrayVib(dcurve, skin_curve); + if (dcurve) { + delete dcurve; + dcurve = NULL; + } + + +// skin_curve.dump("skin_curve"); + + const float chromaPastel = float(params->vibrance.pastels) / 100.0f; + const float chromaSatur = float(params->vibrance.saturated) / 100.0f; + const float p00=0.07f; + const float limitpastelsatur = (static_cast(params->vibrance.psthreshold.value[ThresholdSelector::TS_TOPLEFT]) / 100.0f)*(1.0f-p00) + p00; + const float maxdp=(limitpastelsatur-p00)/4.0f; + const float maxds=(1.0-limitpastelsatur)/4.0f; + const float p0 = p00+maxdp; + const float p1 = p00+2.0f*maxdp; + const float p2 = p00+3.0f*maxdp; + const float s0 = limitpastelsatur + maxds; + const float s1 = limitpastelsatur + 2.0f*maxds; + const float s2 = limitpastelsatur + 3.0f*maxds; + const float transitionweighting = static_cast(params->vibrance.psthreshold.value[ThresholdSelector::TS_BOTTOMLEFT]) / 100.0f; + float chromamean=0.0f; + if(chromaPastel != chromaSatur){ + //if sliders pastels and saturated are different: transition with a double linear interpolation: between p2 and limitpastelsatur, and between limitpastelsatur and s0 + //modify the "mean" point in function of double threshold => differential transition + chromamean = maxdp * (chromaSatur-chromaPastel) / (s0-p2) + chromaPastel; + // move chromaMean up or down depending on transitionCtrl + if (transitionweighting > 0.0f) { + chromamean = (chromaSatur-chromamean) * transitionweighting + chromamean; + } + else if (transitionweighting < 0.0f) { + chromamean = (chromamean-chromaPastel) * transitionweighting + chromamean; + } + } + const float chromaPastel_a = (chromaPastel-chromamean)/(p2-limitpastelsatur); + const float chromaPastel_b = chromaPastel-chromaPastel_a*p2; + + const float chromaSatur_a=(chromaSatur-chromamean)/(s0-limitpastelsatur); + const float chromaSatur_b=chromaSatur-chromaSatur_a*s0; + + const float dhue=0.15f;//hue transition + const float dchr=20.0f;//chroma transition + const float skbeg=-0.05f;//begin hue skin + const float skend=1.60f;//end hue skin + const float xx=0.5f;//soft : between 0.3 and 1.0 + const float ask=65535.0f/(skend-skbeg); + const float bsk=-skbeg*ask; + + + const bool highlight = params->toneCurve.hrenabled;//Get the value if "highlight reconstruction" is activated + const bool protectskins = params->vibrance.protectskins; + const bool avoidcolorshift = params->vibrance.avoidcolorshift; + + TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); + //inverse matrix user select + const double wip[3][3] = { + {wiprof[0][0],wiprof[0][1],wiprof[0][2]}, + {wiprof[1][0],wiprof[1][1],wiprof[1][2]}, + {wiprof[2][0],wiprof[2][1],wiprof[2][2]} + }; + + +#ifdef _DEBUG + MunsellDebugInfo* MunsDebugInfo = NULL; + if (avoidcolorshift) + MunsDebugInfo = new MunsellDebugInfo(); +#pragma omp parallel default(shared) firstprivate(lab, width, height, chromaPastel, chromaSatur, highlight, limitpastelsatur, transitionweighting, protectskins, avoidcolorshift, MunsDebugInfo) reduction(+: negat, moreRGB, negsat, moresat) if (multiThread) +#else #pragma omp parallel default(shared) if (multiThread) -#endif -{ - - float sathue[5],sathue2[4];// adjust sat in function of hue - -/* - // Fitting limitpastelsatur into the real 0.07->1.0 range -// limitpastelsatur = limitpastelsatur*(1.0f-p00) + p00; - float p0,p1,p2;//adapt limit of pyramid to psThreshold - float s0,s1,s2; -*/ - -#ifdef _OPENMP - if (settings->verbose && omp_get_thread_num()==0) { -#else - if (settings->verbose) { -#endif - printf("vibrance: p0=%1.2f p1=%1.2f p2=%1.2f s0=%1.2f s1=%1.2f s2=%1.2f\n", p0,p1,p2,s0,s1,s2); - printf(" pastel=%f satur=%f limit= %1.2f chromamean=%0.5f\n",1.0f+chromaPastel,1.0f+chromaSatur, limitpastelsatur, chromamean); - } - -#pragma omp for schedule(dynamic, 16) - for (int i=0; iL[i][j]/327.68f; - float CC=sqrt(SQR(lab->a[i][j])+ SQR(lab->b[i][j]))/327.68f; +#endif +{ + + float sathue[5],sathue2[4];// adjust sat in function of hue + +/* + // Fitting limitpastelsatur into the real 0.07->1.0 range +// limitpastelsatur = limitpastelsatur*(1.0f-p00) + p00; + float p0,p1,p2;//adapt limit of pyramid to psThreshold + float s0,s1,s2; +*/ + +#ifdef _OPENMP + if (settings->verbose && omp_get_thread_num()==0) { +#else + if (settings->verbose) { +#endif + printf("vibrance: p0=%1.2f p1=%1.2f p2=%1.2f s0=%1.2f s1=%1.2f s2=%1.2f\n", p0,p1,p2,s0,s1,s2); + printf(" pastel=%f satur=%f limit= %1.2f chromamean=%0.5f\n",1.0f+chromaPastel,1.0f+chromaSatur, limitpastelsatur, chromamean); + } + +#pragma omp for schedule(dynamic, 16) + for (int i=0; iL[i][j]/327.68f; + float CC=sqrt(SQR(lab->a[i][j])+ SQR(lab->b[i][j]))/327.68f; float HH=xatan2f(lab->b[i][j],lab->a[i][j]); - float satredu=1.0f; //reduct sat in function of skin - if(protectskins) { - Color::SkinSat (LL, HH, CC, satredu);// for skin colors + float satredu=1.0f; //reduct sat in function of skin + if(protectskins) { + Color::SkinSat (LL, HH, CC, satredu);// for skin colors } - // here we work on Chromaticity and Hue - // variation of Chromaticity ==> saturation via RGB - // Munsell correction, then conversion to Lab - float Lprov=LL; - float Chprov=CC; - float R, G, B; + // here we work on Chromaticity and Hue + // variation of Chromaticity ==> saturation via RGB + // Munsell correction, then conversion to Lab + float Lprov=LL; + float Chprov=CC; + float R, G, B; float2 sincosval; if(CC==0.0f) { sincosval.y = 1.f; @@ -224,245 +224,245 @@ void ImProcFunctions::vibrance (LabImage* lab) { sincosval.y = lab->a[i][j]/(CC*327.68f); sincosval.x = lab->b[i][j]/(CC*327.68f); } - -#ifdef _DEBUG - bool neg=false; - bool more_rgb=false; - //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lprov, Chprov, R, G, B, wip, highlight, 0.15f, 0.98f, neg, more_rgb); - if(neg) negat++; - if(more_rgb) moreRGB++; -#else - //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lprov, Chprov, R, G, B, wip, highlight, 0.15f, 0.98f); -#endif + +#ifdef _DEBUG + bool neg=false; + bool more_rgb=false; + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH, sincosval, Lprov, Chprov, R, G, B, wip, highlight, 0.15f, 0.98f, neg, more_rgb); + if(neg) negat++; + if(more_rgb) moreRGB++; +#else + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH, sincosval, Lprov, Chprov, R, G, B, wip, highlight, 0.15f, 0.98f); +#endif if(Chprov > 6.0f) { const float saturation=SAT(R,G,B); - if(saturation>0.0f) { - if(satredu!=1.0f) { - // for skin, no differentiation - sathue [0]=sathue [1]=sathue [2]=sathue [3]=sathue[4]=1.0f; - sathue2[0]=sathue2[1]=sathue2[2]=sathue2[3] =1.0f; - } else { - //double pyramid: LL and HH - //I try to take into account: Munsell response (human vision) and Gamut..(less response for red): preferably using Prophoto or WideGamut - //blue: -1.80 -3.14 green = 2.1 3.14 green-yellow=1.4 2.1 red:0 1.4 blue-purple:-0.7 -1.4 purple: 0 -0.7 - //these values allow a better and differential response - if(LL < 20.0f) {//more for blue-purple, blue and red modulate - if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.1f;sathue[3]=1.05f;sathue[4]=0.4f;sathue2[0]=1.05f;sathue2[1]=1.1f ;sathue2[2]=1.05f;sathue2[3]=1.0f;}//blue - else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.6f;sathue[1]=1.4f;sathue[2]=1.3f;sathue[3]=1.2f ;sathue[4]=0.4f;sathue2[0]=1.2f ;sathue2[1]=1.15f;sathue2[2]=1.1f ;sathue2[3]=1.0f;}//blue purple 1.2 1.1 - else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;sathue[1]=1.0f;sathue[2]=1.0f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//purple - // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=1.1f;sathue[1]=1.1f;sathue[2]=1.1f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//red 0.8 0.7 - else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.1f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//red 0.8 0.7 - else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.0f;sathue[1]=1.0f;sathue[2]=1.0f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//green yellow 1.2 1.1 - else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.4f;sathue[1]=1.3f;sathue[2]=1.2f;sathue[3]=1.15f;sathue[4]=0.4f;sathue2[0]=1.15f;sathue2[1]=1.1f ;sathue2[2]=1.05f;sathue2[3]=1.0f;}//green - } - else if (LL< 50.0f) {//more for blue and green, less for red and green-yellow - if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.5f;sathue[1]=1.4f;sathue[2]=1.3f;sathue[3]=1.2f ;sathue[4]=0.4f;sathue2[0]=1.2f ;sathue2[1]=1.1f ;sathue2[2]=1.05f;sathue2[3]=1.0f;}//blue - else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.1f;sathue[3]=1.05f;sathue[4]=0.4f;sathue2[0]=1.05f;sathue2[1]=1.05f;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//blue purple 1.2 1.1 - else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;sathue[1]=1.0f;sathue[2]=1.0f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//purple - // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f;sathue[3]=0.8f ;sathue[4]=0.4f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;sathue[1]=1.0f;sathue[2]=0.9f;sathue[3]=0.8f ;sathue[4]=0.4f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.1f;sathue[1]=1.1f;sathue[2]=1.1f;sathue[3]=1.05f;sathue[4]=0.4f;sathue2[0]=0.9f ;sathue2[1]=0.8f ;sathue2[2]=0.7f ;sathue2[3]=0.6f;}//green yellow 1.2 1.1 - else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.5f;sathue[1]=1.4f;sathue[2]=1.3f;sathue[3]=1.2f ;sathue[4]=0.4f;sathue2[0]=1.2f ;sathue2[1]=1.1f ;sathue2[2]=1.05f;sathue2[3]=1.0f;}//green - - } - else if (LL< 80.0f) {//more for green, less for red and green-yellow - if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.15f;sathue[3]=1.1f ;sathue[4]=0.3f;sathue2[0]=1.1f ;sathue2[1]=1.1f ;sathue2[2]=1.05f;sathue2[3]=1.0f;}//blue - else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.15f;sathue[3]=1.1f ;sathue[4]=0.3f;sathue2[0]=1.1f ;sathue2[1]=1.05f;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//blue purple 1.2 1.1 - else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;sathue[1]=1.0f;sathue[2]=1.0f ;sathue[3]=1.0f ;sathue[4]=0.3f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//purple - // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f ;sathue[3]=0.8f ;sathue[4]=0.3f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;sathue[1]=1.0f;sathue[2]=0.9f ;sathue[3]=0.8f ;sathue[4]=0.3f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.1f ;sathue[3]=1.05f;sathue[4]=0.3f;sathue2[0]=1.0f ;sathue2[1]=0.9f ;sathue2[2]=0.8f ;sathue2[3]=0.7f;}//green yellow 1.2 1.1 - else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.6f;sathue[1]=1.4f;sathue[2]=1.3f ;sathue[3]=1.25f;sathue[4]=0.3f;sathue2[0]=1.25f;sathue2[1]=1.2f ;sathue2[2]=1.15f;sathue2[3]=1.05f;}//green - even with Prophoto green are too "little" 1.5 1.3 - } - else /*if (LL>=80.0f)*/ {//more for green-yellow, less for red and purple - if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.0f;sathue[1]=1.0f;sathue[2]=0.9f;sathue[3]=0.8f;sathue[4]=0.2f;sathue2[0]=0.8f;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//blue - else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.0f;sathue[1]=1.0f;sathue[2]=0.9f;sathue[3]=0.8f;sathue[4]=0.2f;sathue2[0]=0.8f;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//blue purple 1.2 1.1 - else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;sathue[1]=1.0f;sathue[2]=1.0f;sathue[3]=0.9f;sathue[4]=0.2f;sathue2[0]=0.9f;sathue2[1]=0.9f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//purple - // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f;sathue[3]=0.8f;sathue[4]=0.2f;sathue2[0]=0.8f;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;sathue[1]=1.0f;sathue[2]=0.9f;sathue[3]=0.8f;sathue[4]=0.2f;sathue2[0]=0.8f;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.6f;sathue[1]=1.5f;sathue[2]=1.4f;sathue[3]=1.2f;sathue[4]=0.2f;sathue2[0]=1.1f;sathue2[1]=1.05f;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//green yellow 1.2 1.1 - else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.4f;sathue[1]=1.3f;sathue[2]=1.2f;sathue[3]=1.1f;sathue[4]=0.2f;sathue2[0]=1.1f;sathue2[1]=1.05f;sathue2[2]=1.05f;sathue2[3]=1.0f;}//green - } + if(saturation>0.0f) { + if(satredu!=1.0f) { + // for skin, no differentiation + sathue [0]=sathue [1]=sathue [2]=sathue [3]=sathue[4]=1.0f; + sathue2[0]=sathue2[1]=sathue2[2]=sathue2[3] =1.0f; + } else { + //double pyramid: LL and HH + //I try to take into account: Munsell response (human vision) and Gamut..(less response for red): preferably using Prophoto or WideGamut + //blue: -1.80 -3.14 green = 2.1 3.14 green-yellow=1.4 2.1 red:0 1.4 blue-purple:-0.7 -1.4 purple: 0 -0.7 + //these values allow a better and differential response + if(LL < 20.0f) {//more for blue-purple, blue and red modulate + if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.1f;sathue[3]=1.05f;sathue[4]=0.4f;sathue2[0]=1.05f;sathue2[1]=1.1f ;sathue2[2]=1.05f;sathue2[3]=1.0f;}//blue + else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.6f;sathue[1]=1.4f;sathue[2]=1.3f;sathue[3]=1.2f ;sathue[4]=0.4f;sathue2[0]=1.2f ;sathue2[1]=1.15f;sathue2[2]=1.1f ;sathue2[3]=1.0f;}//blue purple 1.2 1.1 + else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;sathue[1]=1.0f;sathue[2]=1.0f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//purple + // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=1.1f;sathue[1]=1.1f;sathue[2]=1.1f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//red 0.8 0.7 + else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.1f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//red 0.8 0.7 + else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.0f;sathue[1]=1.0f;sathue[2]=1.0f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//green yellow 1.2 1.1 + else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.4f;sathue[1]=1.3f;sathue[2]=1.2f;sathue[3]=1.15f;sathue[4]=0.4f;sathue2[0]=1.15f;sathue2[1]=1.1f ;sathue2[2]=1.05f;sathue2[3]=1.0f;}//green + } + else if (LL< 50.0f) {//more for blue and green, less for red and green-yellow + if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.5f;sathue[1]=1.4f;sathue[2]=1.3f;sathue[3]=1.2f ;sathue[4]=0.4f;sathue2[0]=1.2f ;sathue2[1]=1.1f ;sathue2[2]=1.05f;sathue2[3]=1.0f;}//blue + else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.1f;sathue[3]=1.05f;sathue[4]=0.4f;sathue2[0]=1.05f;sathue2[1]=1.05f;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//blue purple 1.2 1.1 + else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;sathue[1]=1.0f;sathue[2]=1.0f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//purple + // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f;sathue[3]=0.8f ;sathue[4]=0.4f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;sathue[1]=1.0f;sathue[2]=0.9f;sathue[3]=0.8f ;sathue[4]=0.4f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.1f;sathue[1]=1.1f;sathue[2]=1.1f;sathue[3]=1.05f;sathue[4]=0.4f;sathue2[0]=0.9f ;sathue2[1]=0.8f ;sathue2[2]=0.7f ;sathue2[3]=0.6f;}//green yellow 1.2 1.1 + else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.5f;sathue[1]=1.4f;sathue[2]=1.3f;sathue[3]=1.2f ;sathue[4]=0.4f;sathue2[0]=1.2f ;sathue2[1]=1.1f ;sathue2[2]=1.05f;sathue2[3]=1.0f;}//green + + } + else if (LL< 80.0f) {//more for green, less for red and green-yellow + if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.15f;sathue[3]=1.1f ;sathue[4]=0.3f;sathue2[0]=1.1f ;sathue2[1]=1.1f ;sathue2[2]=1.05f;sathue2[3]=1.0f;}//blue + else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.15f;sathue[3]=1.1f ;sathue[4]=0.3f;sathue2[0]=1.1f ;sathue2[1]=1.05f;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//blue purple 1.2 1.1 + else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;sathue[1]=1.0f;sathue[2]=1.0f ;sathue[3]=1.0f ;sathue[4]=0.3f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//purple + // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f ;sathue[3]=0.8f ;sathue[4]=0.3f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;sathue[1]=1.0f;sathue[2]=0.9f ;sathue[3]=0.8f ;sathue[4]=0.3f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.3f;sathue[1]=1.2f;sathue[2]=1.1f ;sathue[3]=1.05f;sathue[4]=0.3f;sathue2[0]=1.0f ;sathue2[1]=0.9f ;sathue2[2]=0.8f ;sathue2[3]=0.7f;}//green yellow 1.2 1.1 + else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.6f;sathue[1]=1.4f;sathue[2]=1.3f ;sathue[3]=1.25f;sathue[4]=0.3f;sathue2[0]=1.25f;sathue2[1]=1.2f ;sathue2[2]=1.15f;sathue2[3]=1.05f;}//green - even with Prophoto green are too "little" 1.5 1.3 + } + else /*if (LL>=80.0f)*/ {//more for green-yellow, less for red and purple + if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.0f;sathue[1]=1.0f;sathue[2]=0.9f;sathue[3]=0.8f;sathue[4]=0.2f;sathue2[0]=0.8f;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//blue + else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.0f;sathue[1]=1.0f;sathue[2]=0.9f;sathue[3]=0.8f;sathue[4]=0.2f;sathue2[0]=0.8f;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//blue purple 1.2 1.1 + else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;sathue[1]=1.0f;sathue[2]=1.0f;sathue[3]=0.9f;sathue[4]=0.2f;sathue2[0]=0.9f;sathue2[1]=0.9f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//purple + // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f;sathue[3]=0.8f;sathue[4]=0.2f;sathue2[0]=0.8f;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;sathue[1]=1.0f;sathue[2]=0.9f;sathue[3]=0.8f;sathue[4]=0.2f;sathue2[0]=0.8f;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.6f;sathue[1]=1.5f;sathue[2]=1.4f;sathue[3]=1.2f;sathue[4]=0.2f;sathue2[0]=1.1f;sathue2[1]=1.05f;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//green yellow 1.2 1.1 + else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.4f;sathue[1]=1.3f;sathue[2]=1.2f;sathue[3]=1.1f;sathue[4]=0.2f;sathue2[0]=1.1f;sathue2[1]=1.05f;sathue2[2]=1.05f;sathue2[3]=1.0f;}//green + } } - float chmodpastel,chmodsat; - // variables to improve transitions - float pa, pb;// transition = pa*saturation + pb - float chl00 = chromaPastel*satredu*sathue[4]; - float chl0 = chromaPastel*satredu*sathue[0]; - float chl1 = chromaPastel*satredu*sathue[1]; - float chl2 = chromaPastel*satredu*sathue[2]; - float chl3 = chromaPastel*satredu*sathue[3]; - float chs0 = chromaSatur*satredu*sathue2[0]; - float chs1 = chromaSatur*satredu*sathue2[1]; - float chs2 = chromaSatur*satredu*sathue2[2]; - float chs3 = chromaSatur*satredu*sathue2[3]; - float s3 = 1.0f; - // We handle only positive values here ; improve transitions - if (saturation < p00) chmodpastel = chl00 ; //neutral tones - else if (saturation < p0 ) { pa=(chl00-chl0)/(p00-p0); pb=chl00-pa*p00; chmodpastel = pa*saturation + pb; } - else if (saturation < p1) { pa=(chl0-chl1)/(p0-p1); pb=chl0-pa*p0; chmodpastel = pa*saturation + pb; } - else if (saturation < p2) { pa=(chl1-chl2)/(p1-p2); pb=chl1-pa*p1; chmodpastel = pa*saturation + pb; } - else if (saturation < limitpastelsatur) { pa=(chl2- chl3)/(p2-limitpastelsatur); pb=chl2-pa*p2; chmodpastel = pa*saturation + pb; } - else if (saturation < s0) { pa=(chl3-chs0)/(limitpastelsatur-s0) ; pb=chl3-pa*limitpastelsatur; chmodsat = pa*saturation + pb; } - else if (saturation < s1) { pa=(chs0-chs1)/(s0-s1); pb=chs0-pa*s0; chmodsat = pa*saturation + pb; } - else if (saturation < s2) { pa=(chs1-chs2)/(s1-s2); pb=chs1-pa*s1; chmodsat = pa*saturation + pb; } - else { pa=(chs2-chs3)/(s2-s3); pb=chs2-pa*s2; chmodsat = pa*saturation + pb; } - - if(chromaPastel != chromaSatur){ - - // Pastels - if(saturation > p2 && saturation < limitpastelsatur) { - float newchromaPastel = chromaPastel_a*saturation + chromaPastel_b; - chmodpastel = newchromaPastel*satredu*sathue[3]; - } - - // Saturated - if(saturation < s0 && saturation >=limitpastelsatur) { - float newchromaSatur=chromaSatur_a*saturation + chromaSatur_b; - chmodsat = newchromaSatur*satredu*sathue2[0]; - } - }// end transition - - if (saturation <= limitpastelsatur) { + float chmodpastel,chmodsat; + // variables to improve transitions + float pa, pb;// transition = pa*saturation + pb + float chl00 = chromaPastel*satredu*sathue[4]; + float chl0 = chromaPastel*satredu*sathue[0]; + float chl1 = chromaPastel*satredu*sathue[1]; + float chl2 = chromaPastel*satredu*sathue[2]; + float chl3 = chromaPastel*satredu*sathue[3]; + float chs0 = chromaSatur*satredu*sathue2[0]; + float chs1 = chromaSatur*satredu*sathue2[1]; + float chs2 = chromaSatur*satredu*sathue2[2]; + float chs3 = chromaSatur*satredu*sathue2[3]; + float s3 = 1.0f; + // We handle only positive values here ; improve transitions + if (saturation < p00) chmodpastel = chl00 ; //neutral tones + else if (saturation < p0 ) { pa=(chl00-chl0)/(p00-p0); pb=chl00-pa*p00; chmodpastel = pa*saturation + pb; } + else if (saturation < p1) { pa=(chl0-chl1)/(p0-p1); pb=chl0-pa*p0; chmodpastel = pa*saturation + pb; } + else if (saturation < p2) { pa=(chl1-chl2)/(p1-p2); pb=chl1-pa*p1; chmodpastel = pa*saturation + pb; } + else if (saturation < limitpastelsatur) { pa=(chl2- chl3)/(p2-limitpastelsatur); pb=chl2-pa*p2; chmodpastel = pa*saturation + pb; } + else if (saturation < s0) { pa=(chl3-chs0)/(limitpastelsatur-s0) ; pb=chl3-pa*limitpastelsatur; chmodsat = pa*saturation + pb; } + else if (saturation < s1) { pa=(chs0-chs1)/(s0-s1); pb=chs0-pa*s0; chmodsat = pa*saturation + pb; } + else if (saturation < s2) { pa=(chs1-chs2)/(s1-s2); pb=chs1-pa*s1; chmodsat = pa*saturation + pb; } + else { pa=(chs2-chs3)/(s2-s3); pb=chs2-pa*s2; chmodsat = pa*saturation + pb; } + + if(chromaPastel != chromaSatur){ + + // Pastels + if(saturation > p2 && saturation < limitpastelsatur) { + float newchromaPastel = chromaPastel_a*saturation + chromaPastel_b; + chmodpastel = newchromaPastel*satredu*sathue[3]; + } + + // Saturated + if(saturation < s0 && saturation >=limitpastelsatur) { + float newchromaSatur=chromaSatur_a*saturation + chromaSatur_b; + chmodsat = newchromaSatur*satredu*sathue2[0]; + } + }// end transition + + if (saturation <= limitpastelsatur) { if (chmodpastel > 2.0f ) - chmodpastel = 2.0f; //avoid too big values + chmodpastel = 2.0f; //avoid too big values else if(chmodpastel < -0.93f) - chmodpastel =-0.93f; //avoid negative values - - Chprov *=(1.0f+chmodpastel); + chmodpastel =-0.93f; //avoid negative values + + Chprov *=(1.0f+chmodpastel); if(Chprov<6.0f) - Chprov=6.0f; - } - else { //if (saturation > limitpastelsatur) + Chprov=6.0f; + } + else { //if (saturation > limitpastelsatur) if (chmodsat > 1.8f ) - chmodsat = 1.8f; //saturated + chmodsat = 1.8f; //saturated else if(chmodsat < -0.93f) - chmodsat =-0.93f; - - Chprov *= 1.0f+chmodsat; + chmodsat =-0.93f; + + Chprov *= 1.0f+chmodsat; if(Chprov < 6.0f) - Chprov=6.0f; + Chprov=6.0f; } } - } + } - bool hhModified = false; - // Vibrance's Skin curve - if(skinCurveIsSet) { - if (HH>skbeg && HH transition - float HHsk=ask*HH+bsk; - float Hn=(skin_curve[HHsk]-bsk)/ask; - float Hc=(Hn*xx+HH*(1.0f-xx)); + bool hhModified = false; + // Vibrance's Skin curve + if(skinCurveIsSet) { + if (HH>skbeg && HH transition + float HHsk=ask*HH+bsk; + float Hn=(skin_curve[HHsk]-bsk)/ask; + float Hc=(Hn*xx+HH*(1.0f-xx)); HH=Hc; - hhModified = true; - } - else if(Chprov < (60.0f+dchr)) {//transition chroma - float HHsk=ask*HH+bsk; - float Hn=(skin_curve[HHsk]-bsk)/ask; - float Hc=(Hn*xx+HH*(1.0f-xx)); - float aa= (HH-Hc)/dchr ; float bb= HH-(60.0f+dchr)*aa; + hhModified = true; + } + else if(Chprov < (60.0f+dchr)) {//transition chroma + float HHsk=ask*HH+bsk; + float Hn=(skin_curve[HHsk]-bsk)/ask; + float Hc=(Hn*xx+HH*(1.0f-xx)); + float aa= (HH-Hc)/dchr ; float bb= HH-(60.0f+dchr)*aa; HH=aa*Chprov+bb; - hhModified = true; - } - } - //transition hue - else if(HH>(skbeg-dhue) && HH<=skbeg && Chprov < (60.0f+dchr*0.5f)) { - float HHsk=ask*skbeg+bsk; - float Hn=(skin_curve[HHsk]-bsk)/ask; - float Hcc=(Hn*xx+skbeg*(1.0f-xx)); - float adh=(Hcc-(skbeg-dhue))/(dhue); - float bdh=Hcc-adh*skbeg; + hhModified = true; + } + } + //transition hue + else if(HH>(skbeg-dhue) && HH<=skbeg && Chprov < (60.0f+dchr*0.5f)) { + float HHsk=ask*skbeg+bsk; + float Hn=(skin_curve[HHsk]-bsk)/ask; + float Hcc=(Hn*xx+skbeg*(1.0f-xx)); + float adh=(Hcc-(skbeg-dhue))/(dhue); + float bdh=Hcc-adh*skbeg; HH=adh*HH+bdh; - hhModified = true; - } - else if(HH>=skend && HH<(skend+dhue) && Chprov < (60.0f+dchr*0.5f)) { - float HHsk=ask*skend+bsk; - float Hn=(skin_curve[HHsk]-bsk)/ask; - float Hcc=(Hn*xx+skend*(1.0f-xx)); - float adh=(skend+dhue-Hcc)/(dhue); - float bdh=Hcc-adh*skend; + hhModified = true; + } + else if(HH>=skend && HH<(skend+dhue) && Chprov < (60.0f+dchr*0.5f)) { + float HHsk=ask*skend+bsk; + float Hn=(skin_curve[HHsk]-bsk)/ask; + float Hcc=(Hn*xx+skend*(1.0f-xx)); + float adh=(skend+dhue-Hcc)/(dhue); + float bdh=Hcc-adh*skend; HH=adh*HH+bdh; - hhModified = true; - } - } // end skin hue - - //Munsell correction + hhModified = true; + } + } // end skin hue + + //Munsell correction // float2 sincosval; if(!avoidcolorshift && hhModified) - sincosval = xsincosf(HH); - float aprovn,bprovn; - bool inGamut; - do { - inGamut=true; - if(avoidcolorshift) { - float correctionHue=0.0f; - float correctlum=0.0f; - -#ifdef _DEBUG - Color::AllMunsellLch(/*lumaMuns*/false, Lprov,Lprov,HH,Chprov,CC,correctionHue,correctlum, MunsDebugInfo); -#else - Color::AllMunsellLch(/*lumaMuns*/false, Lprov,Lprov,HH,Chprov,CC,correctionHue,correctlum); + sincosval = xsincosf(HH); + float aprovn,bprovn; + bool inGamut; + do { + inGamut=true; + if(avoidcolorshift) { + float correctionHue=0.0f; + float correctlum=0.0f; + +#ifdef _DEBUG + Color::AllMunsellLch(/*lumaMuns*/false, Lprov,Lprov,HH,Chprov,CC,correctionHue,correctlum, MunsDebugInfo); +#else + Color::AllMunsellLch(/*lumaMuns*/false, Lprov,Lprov,HH,Chprov,CC,correctionHue,correctlum); #endif if(correctionHue != 0.f || hhModified) { sincosval = xsincosf(HH+correctionHue); hhModified = false; - } - } - aprovn=Chprov*sincosval.y; - bprovn=Chprov*sincosval.x; - - float fyy = (0.00862069f *Lprov )+ 0.137932f; - float fxx = (0.002f * aprovn) + fyy; - float fzz = fyy - (0.005f * bprovn); - float xx_ = 65535.f * Color::f2xyz(fxx)*Color::D50x; - // float yy_ = 65535.0f * Color::f2xyz(fyy); - float zz_ = 65535.f * Color::f2xyz(fzz)*Color::D50z; - float yy_ = 65535.f * ((Lprov>Color::epskap) ? fyy*fyy*fyy : Lprov/Color::kappa); - - Color::xyz2rgb(xx_,yy_,zz_,R,G,B,wip); - - if(R<0.0f || G<0.0f || B<0.0f) { -#ifdef _DEBUG - negsat++; -#endif - Chprov *= 0.98f; - inGamut = false; - } - - // if "highlight reconstruction" enabled don't control Gamut for highlights - if((!highlight) && (R>65535.0f || G>65535.0f || B>65535.0f)) { -#ifdef _DEBUG - moresat++; -#endif - Chprov *= 0.98f; - inGamut = false; - } - } while (!inGamut); - - //put new values in Lab - lab->L[i][j]=Lprov*327.68f; - lab->a[i][j]=aprovn*327.68f; - lab->b[i][j]=bprovn*327.68f; - } - -} // end of parallelization - -#ifdef _DEBUG - t2e.set(); - if (settings->verbose) { - printf("Vibrance (performed in %d usec):\n", t2e.etime(t1e)); - printf(" Gamut: G1negat=%iiter G165535=%iiter G2negsat=%iiter G265535=%iiter\n",negat,moreRGB,negsat,moresat); - if (MunsDebugInfo) - printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); - } - if (MunsDebugInfo) - delete MunsDebugInfo; -#endif - -} - - -} + } + } + aprovn=Chprov*sincosval.y; + bprovn=Chprov*sincosval.x; + + float fyy = (0.00862069f *Lprov )+ 0.137932f; + float fxx = (0.002f * aprovn) + fyy; + float fzz = fyy - (0.005f * bprovn); + float xx_ = 65535.f * Color::f2xyz(fxx)*Color::D50x; + // float yy_ = 65535.0f * Color::f2xyz(fyy); + float zz_ = 65535.f * Color::f2xyz(fzz)*Color::D50z; + float yy_ = 65535.f * ((Lprov>Color::epskap) ? fyy*fyy*fyy : Lprov/Color::kappa); + + Color::xyz2rgb(xx_,yy_,zz_,R,G,B,wip); + + if(R<0.0f || G<0.0f || B<0.0f) { +#ifdef _DEBUG + negsat++; +#endif + Chprov *= 0.98f; + inGamut = false; + } + + // if "highlight reconstruction" enabled don't control Gamut for highlights + if((!highlight) && (R>65535.0f || G>65535.0f || B>65535.0f)) { +#ifdef _DEBUG + moresat++; +#endif + Chprov *= 0.98f; + inGamut = false; + } + } while (!inGamut); + + //put new values in Lab + lab->L[i][j]=Lprov*327.68f; + lab->a[i][j]=aprovn*327.68f; + lab->b[i][j]=bprovn*327.68f; + } + +} // end of parallelization + +#ifdef _DEBUG + t2e.set(); + if (settings->verbose) { + printf("Vibrance (performed in %d usec):\n", t2e.etime(t1e)); + printf(" Gamut: G1negat=%iiter G165535=%iiter G2negsat=%iiter G265535=%iiter\n",negat,moreRGB,negsat,moresat); + if (MunsDebugInfo) + printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); + } + if (MunsDebugInfo) + delete MunsDebugInfo; +#endif + +} + + +} diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index c192ce1f4..80cc5206d 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -1,3018 +1,3018 @@ -//////////////////////////////////////////////////////////////// -// -// -// -// -// code dated: December , 2014 -// -// Ipwaveletcc is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// * 2014 Jacques Desmis -// * 2014 Ingo Weyrich - -// -//////////////////////////////////////////////////////////////// - - - -#include -#include "../rtgui/threadutils.h" - -#include "rtengine.h" -#include "improcfun.h" -#include "LUT.h" -#include "array2D.h" -#include "boxblur.h" -#include "rt_math.h" -#include "mytime.h" -#include "sleef.c" -#include "opthelper.h" -#include "StopWatch.h" -#include "EdgePreservingDecomposition.h" - -#ifdef _OPENMP -#include -#endif - -#include "cplx_wavelet_dec.h" - -#define TS 64 // Tile size -#define offset 25 // shift between tiles -#define fTS ((TS/2+1)) // second dimension of Fourier tiles -#define blkrad 1 // radius of block averaging - -#define PIX_SORT(a,b) { if ((a)>(b)) {temp=(a);(a)=(b);(b)=temp;} } - -#define med3(a0,a1,a2,a3,a4,a5,a6,a7,a8,median) { \ -pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; pp[5]=a5; pp[6]=a6; pp[7]=a7; pp[8]=a8; \ -PIX_SORT(pp[1],pp[2]); PIX_SORT(pp[4],pp[5]); PIX_SORT(pp[7],pp[8]); \ -PIX_SORT(pp[0],pp[1]); PIX_SORT(pp[3],pp[4]); PIX_SORT(pp[6],pp[7]); \ -PIX_SORT(pp[1],pp[2]); PIX_SORT(pp[4],pp[5]); PIX_SORT(pp[7],pp[8]); \ -PIX_SORT(pp[0],pp[3]); PIX_SORT(pp[5],pp[8]); PIX_SORT(pp[4],pp[7]); \ -PIX_SORT(pp[3],pp[6]); PIX_SORT(pp[1],pp[4]); PIX_SORT(pp[2],pp[5]); \ -PIX_SORT(pp[4],pp[7]); PIX_SORT(pp[4],pp[2]); PIX_SORT(pp[6],pp[4]); \ -PIX_SORT(pp[4],pp[2]); median=pp[4];} //pp4 = median - - -#define med2(a0,a1,a2,a3,a4,median) { \ -pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; \ -PIX_SORT(pp[0],pp[1]) ; PIX_SORT(pp[3],pp[4]) ; PIX_SORT(pp[0],pp[3]) ;\ -PIX_SORT(pp[1],pp[4]) ; PIX_SORT(pp[1],pp[2]) ; PIX_SORT(pp[2],pp[3]) ;\ -PIX_SORT(pp[1],pp[2]) ; median=pp[2] ;} - - -#define epsilon 0.001f/(TS*TS) //tolerance - - -namespace rtengine { - -extern const Settings* settings; - -struct cont_params { - float mul[10]; - int chrom; - int chro; - int contrast; - float th; - float thH; - float conres; - float conresH; - float chrores; - float hueres; - float sky; - float b_l,t_l,b_r,t_r; - float b_ly,t_ly,b_ry,t_ry; - float b_lsl,t_lsl,b_rsl,t_rsl; - float b_lhl,t_lhl,b_rhl,t_rhl; - float edg_low, edg_mean, edg_sd, edg_max; - float lev0s, lev0n, lev1s, lev1n, lev2s, lev2n, lev3s, lev3n; - float b_lpast,t_lpast,b_rpast,t_rpast; - float b_lsat,t_lsat,b_rsat,t_rsat; - int rad; - int val; - int til; - int numlevH, numlevS; - float mulC[9]; - float mulopaRG[9]; - float mulopaBY[9]; - bool curv; - bool opaBY; - bool opaRG; - bool edgcurv; - bool diagcurv; - int CHmet; - int CHSLmet; - int EDmet; - bool HSmet; - bool avoi; - float strength; - int reinforce; - bool detectedge; - int backm; - float eddet; - float eddetthr; - bool lips; - float eddetthrHi; - bool link; - bool lip3; - bool tonemap; - bool diag; - int TMmeth; - float tmstrength; - float balan; - int ite; - int contmet; - bool opaW; - int BAmet; - bool bam; - float blhigh; - float grhigh; - float blmed; - float grmed; - float bllow; - float grlow; - bool cbena; - bool contena; - bool chromena; - bool edgeena; - bool resena; - bool finena; - bool toningena; - bool noiseena; - int maxilev; - float edgsens; - float edgampl; - int neigh; - bool lipp; -}; - -int wavNestedLevels = 1; - - -SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const procparams::WaveletParams & waparams, const WavCurve & wavCLVCcurve, const WavOpacityCurveRG & waOpacityCurveRG, const WavOpacityCurveBY & waOpacityCurveBY, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveWL & waOpacityCurveWL, LUTf &wavclCurve, bool wavcontlutili, int skip) - - -{ - MyTime t1e,t2e ; - t1e.set(); - -#ifdef _DEBUG - // init variables to display Munsell corrections - MunsellDebugInfo* MunsDebugInfo = new MunsellDebugInfo(); -#endif - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); - double wip[3][3] = { - {wiprof[0][0],wiprof[0][1],wiprof[0][2]}, - {wiprof[1][0],wiprof[1][1],wiprof[1][2]}, - {wiprof[2][0],wiprof[2][1],wiprof[2][2]} - }; - const short int imheight=lab->H, imwidth=lab->W; - struct cont_params cp; - cp.avoi = params->wavelet.avoid; - if(params->wavelet.Medgreinf=="more") cp.reinforce = 1; - if(params->wavelet.Medgreinf=="none") cp.reinforce = 2; - if(params->wavelet.Medgreinf=="less") cp.reinforce = 3; - - if(params->wavelet.NPmethod=="none") cp.lip3 = false; - if(params->wavelet.NPmethod=="low") {cp.lip3 = true;cp.neigh=0;} - if(params->wavelet.NPmethod=="high") {cp.lip3 = true;cp.neigh=1;} - - cp.lipp = params->wavelet.lipst; - cp.diag = params->wavelet.tmr; - cp.balan = (float)params->wavelet.balance; - cp.ite = params->wavelet.iter; - cp.tonemap=false; - cp.bam=false; - if(params->wavelet.tmrs==0) cp.tonemap=false; - else cp.tonemap=true; - /*else if(params->wavelet.TMmethod=="std") {cp.TMmeth=1;cp.tonemap=true;} - else if(params->wavelet.TMmethod=="high") {cp.TMmeth=2;cp.tonemap=true;} - else if(params->wavelet.TMmethod=="lowhigh") {cp.TMmeth=3;cp.tonemap=true;} - */ - if(params->wavelet.TMmethod=="cont") cp.contmet=1; - else if(params->wavelet.TMmethod=="tm") cp.contmet=2; - - if(params->wavelet.BAmethod!="none") cp.bam=true; - if(params->wavelet.BAmethod=="sli") cp.BAmet=1; - if(params->wavelet.BAmethod=="cur") cp.BAmet=2; - - cp.tmstrength=params->wavelet.tmrs; - //cp.tonemap = params->wavelet.tmr; - cp.contena=true; - cp.contena=params->wavelet.expcontrast; - cp.chromena=true; - cp.chromena=params->wavelet.expchroma; - cp.edgeena=true; - cp.edgeena=params->wavelet.expedge; - cp.resena=true; - cp.resena=params->wavelet.expresid; - cp.finena=true; - cp.finena=params->wavelet.expfinal; - cp.toningena=true; - cp.toningena=params->wavelet.exptoning; - cp.noiseena=true; - cp.noiseena=params->wavelet.expnoise; - - if(params->wavelet.Backmethod=="black") cp.backm= 0; - if(params->wavelet.Backmethod=="grey") cp.backm = 1; - if(params->wavelet.Backmethod=="resid") cp.backm = 2; - cp.link=params->wavelet.linkedg; - cp.eddet=(float) params->wavelet.edgedetect; - cp.eddetthr=(float) params->wavelet.edgedetectthr; - cp.eddetthrHi=(float) params->wavelet.edgedetectthr2; - - cp.edgsens=60.f; - cp.edgampl=10.f; - if(cp.lipp) { - cp.edgsens=(float) params->wavelet.edgesensi; - cp.edgampl=(float) params->wavelet.edgeampli; - } - int N=imheight*imwidth; - int maxmul=params->wavelet.thres; - cp.maxilev=maxmul; - static const float scales[10] = {1.f,2.f,4.f,8.f,16.f,32.f,64.f,128.f,256.f,512.f}; - float scaleskip[10]; - for(int sc=0;sc<10;sc++) - scaleskip[sc]=scales[sc]/skip; - float atten0 = 0.40f; - float atten123=0.90f; - - //int DaubLen = settings->daubech ? 8 : 6; - int DaubLen; - if(params->wavelet.daubcoeffmethod=="2_") DaubLen=4; - if(params->wavelet.daubcoeffmethod=="4_") DaubLen=6; - if(params->wavelet.daubcoeffmethod=="6_") DaubLen=8; - if(params->wavelet.daubcoeffmethod=="10_") DaubLen=12; - if(params->wavelet.daubcoeffmethod=="14_") DaubLen=16; - - cp.CHSLmet=1; -// if(params->wavelet.CHSLmethod=="SL") cp.CHSLmet=1; -// if(params->wavelet.CHSLmethod=="CU") cp.CHSLmet=2; - cp.EDmet=1; - if(params->wavelet.EDmethod=="SL") cp.EDmet=1; - if(params->wavelet.EDmethod=="CU") cp.EDmet=2; - - cp.cbena= params->wavelet.cbenab; - cp.blhigh=(float)params->wavelet.bluehigh; - cp.grhigh=(float)params->wavelet.greenhigh; - cp.blmed=(float)params->wavelet.bluemed; - cp.grmed=(float)params->wavelet.greenmed; - cp.bllow=(float)params->wavelet.bluelow; - cp.grlow=(float)params->wavelet.greenlow; - cp.curv=false; - cp.edgcurv=false; - cp.diagcurv=false; - cp.opaRG=false; - cp.opaBY=false; - cp.opaW=false; - cp.CHmet=0; - cp.HSmet=false; - if(params->wavelet.CHmethod=="with") cp.CHmet=1; - if(params->wavelet.CHmethod=="link") cp.CHmet=2; - if(params->wavelet.HSmethod=="with") cp.HSmet=true; - - cp.strength = min(1.f,max(0.f,((float)params->wavelet.strength / 100.f))); - - for(int m=0;mverbose) printf("Wav mul 0=%f 1=%f 2=%f 3=%f 4=%f 5=%f 6=%f 7=%f 8=%f 9=%f\n",cp.mul[0],cp.mul[1],cp.mul[2],cp.mul[3],cp.mul[4],cp.mul[5],cp.mul[6],cp.mul[7],cp.mul[8],cp.mul[9]); - for(int sc=0;sc<9;sc++) {//reduce strength if zoom < 100% for chroma and tuning - if(sc==0) {if(scaleskip[sc] < 1.f) {cp.mulC[sc]*=(atten0*scaleskip[sc]);cp.mulopaRG[sc]*=(atten0*scaleskip[sc]);cp.mulopaBY[sc]*=(atten0*scaleskip[sc]);}} - else {if(scaleskip[sc] < 1.f) {cp.mulC[sc]*=(atten123*scaleskip[sc]);cp.mulopaRG[sc]*=(atten123*scaleskip[sc]);cp.mulopaBY[sc]*=(atten123*scaleskip[sc]);}} - } - - cp.chro=waparams.chro; - cp.chrom=waparams.chroma; - cp.contrast=waparams.contrast; - cp.rad=waparams.edgrad; - cp.val=waparams.edgval; - cp.til=waparams.edgthresh; - - cp.conres=waparams.rescon; - cp.conresH=waparams.resconH; - cp.chrores=waparams.reschro; - //cp.hueres=waparams.reshue; - cp.hueres=2.f; - cp.th=float(waparams.thr); - cp.thH=float(waparams.thrH); - cp.sky=waparams.sky; - //skin - cp.b_l = static_cast(params->wavelet.hueskin.value[0]) / 100.0f; - cp.t_l = static_cast(params->wavelet.hueskin.value[1]) / 100.0f; - cp.b_r = static_cast(params->wavelet.hueskin.value[2]) / 100.0f; - cp.t_r = static_cast(params->wavelet.hueskin.value[3]) / 100.0f; - - cp.b_ly = static_cast(params->wavelet.hueskin2.value[0]) / 100.0f; - cp.t_ly = static_cast(params->wavelet.hueskin2.value[1]) / 100.0f; - cp.b_ry = static_cast(params->wavelet.hueskin2.value[2]) / 100.0f; - cp.t_ry = static_cast(params->wavelet.hueskin2.value[3]) / 100.0f; - cp.numlevH=params->wavelet.threshold; - - //shadows - cp.b_lsl = static_cast(params->wavelet.bllev.value[0]); - cp.t_lsl = static_cast(params->wavelet.bllev.value[1]); - cp.b_rsl = static_cast(params->wavelet.bllev.value[2]); - cp.t_rsl = static_cast(params->wavelet.bllev.value[3]); - cp.numlevS=params->wavelet.threshold2; - int maxlevS=9-cp.numlevH; - cp.numlevS = MIN(cp.numlevS,maxlevS); - //printf("levHigh=%d levShad=%d\n",cp.numlevH,cp.numlevS); - //highlight - cp.b_lhl = static_cast(params->wavelet.hllev.value[0]); - cp.t_lhl = static_cast(params->wavelet.hllev.value[1]); - cp.b_rhl = static_cast(params->wavelet.hllev.value[2]); - cp.t_rhl = static_cast(params->wavelet.hllev.value[3]); - //printf("BL=%f TL=%f BR=%f TR=%f\n",cp.b_lhl,cp.t_lhl,cp.b_rhl,cp.t_rhl); - //pastel - cp.b_lpast = static_cast(params->wavelet.pastlev.value[0]); - cp.t_lpast = static_cast(params->wavelet.pastlev.value[1]); - cp.b_rpast = static_cast(params->wavelet.pastlev.value[2]); - cp.t_rpast = static_cast(params->wavelet.pastlev.value[3]); - //saturated - cp.b_lsat = static_cast(params->wavelet.satlev.value[0]); - cp.t_lsat = static_cast(params->wavelet.satlev.value[1]); - cp.b_rsat = static_cast(params->wavelet.satlev.value[2]); - cp.t_rsat = static_cast(params->wavelet.satlev.value[3]); - //edge local contrast - cp.edg_low = static_cast(params->wavelet.edgcont.value[0]); - cp.edg_mean = static_cast(params->wavelet.edgcont.value[1]); - cp.edg_max = static_cast(params->wavelet.edgcont.value[2]); - cp.edg_sd = static_cast(params->wavelet.edgcont.value[3]); - //level noise - cp.lev0s =static_cast(params->wavelet.level0noise.value[0]); - cp.lev0n =static_cast(params->wavelet.level0noise.value[1]); - cp.lev1s =static_cast(params->wavelet.level1noise.value[0]); - cp.lev1n =static_cast(params->wavelet.level1noise.value[1]); - cp.lev2s =static_cast(params->wavelet.level2noise.value[0]); - cp.lev2n =static_cast(params->wavelet.level2noise.value[1]); - cp.lev3s =static_cast(params->wavelet.level3noise.value[0]); - cp.lev3n =static_cast(params->wavelet.level3noise.value[1]); - - cp.detectedge = false; - cp.detectedge = params->wavelet.medianlev; - //printf("low=%f mean=%f sd=%f max=%f\n",cp.edg_low,cp.edg_mean,cp.edg_sd,cp.edg_max); - int minwin=min(imwidth,imheight); - int maxlevelcrop=9; - if(cp.mul[9]!=0) - maxlevelcrop=10; - // adap maximum level wavelet to size of crop - if(minwin*skip < 1024) maxlevelcrop = 9;//sampling wavelet 512 - if(minwin*skip < 512) maxlevelcrop = 8;//sampling wavelet 256 - if(minwin*skip < 256) maxlevelcrop = 7;//sampling 128 - if(minwin*skip < 128) maxlevelcrop = 6; - if(minwin < 64) maxlevelcrop = 5; - // printf("minwin=%d maxcrop=%d\n",minwin, maxlevelcrop); - - int levwav=params->wavelet.thres; - if(levwav==9 && cp.mul[9]!=0) levwav=10; - levwav=min(maxlevelcrop,levwav); - // determine number of levels to process. - // for(levwav=min(maxlevelcrop,levwav);levwav>0;levwav--) - // if(cp.mul[levwav-1]!=0.f || cp.curv) - // if(cp.mul[levwav-1]!=0.f) - // break; - // I suppress this fonctionality ==> crash for level < 3 - if(levwav<1) - return; // nothing to do - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // begin tile processing of image - - //output buffer - int realtile; - if(params->wavelet.Tilesmethod=="big") realtile=22; - if(params->wavelet.Tilesmethod=="lit") realtile=12; - - int tilesize; - int overlap; - tilesize = 1024; - overlap = 128; - //tilesize=128*params->wavelet.tiles; - tilesize=128*realtile; - //overlap=(int) tilesize*params->wavelet.overl; - overlap=(int) tilesize*0.125f; - // printf("overl=%d\n",overlap); - int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; - if(params->wavelet.Tilesmethod=="full") kall=0; - Tile_calc (tilesize, overlap, kall, imwidth, imheight, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip); - - const int numtiles = numtiles_W*numtiles_H; - LabImage * dsttmp; - if(numtiles == 1) { - dsttmp = dst; - } else { - dsttmp = new LabImage(imwidth,imheight); - for (int n=0; n<3*imwidth*imheight; n++) dsttmp->data[n] = 0; - } - //now we have tile dimensions, overlaps - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - int minsizetile=min(tilewidth, tileheight); - int maxlev2=10; - if(minsizetile < 1024 && levwav==10) maxlev2 = 9; - if(minsizetile < 512) maxlev2 = 8; - if(minsizetile < 256) maxlev2 = 7; - if(minsizetile < 128) maxlev2 = 6; - levwav=min(maxlev2,levwav); - - //printf("levwav = %d\n",levwav); - - int numthreads = 1; - int maxnumberofthreadsforwavelet =0; - //reduce memory for big tile size - if(kall!=0) { - if(realtile <= 22) maxnumberofthreadsforwavelet=2; - if(realtile <= 20) maxnumberofthreadsforwavelet=3; - if(realtile <= 18) maxnumberofthreadsforwavelet=4; - if(realtile <= 16) maxnumberofthreadsforwavelet=6; - if(realtile <= 14) maxnumberofthreadsforwavelet=8; - //printf("maxNRT=%d\n",maxnumberofthreadsforwavelet); - if((maxnumberofthreadsforwavelet==6 || maxnumberofthreadsforwavelet==8) && levwav==10) maxnumberofthreadsforwavelet-=2; - if(levwav <=7 && maxnumberofthreadsforwavelet ==8) maxnumberofthreadsforwavelet=0; - } - //printf("maxthre=%d\n",maxnumberofthreadsforwavelet); - -#ifdef _OPENMP - // Calculate number of tiles. If less than omp_get_max_threads(), then limit num_threads to number of tiles - if( options.rgbDenoiseThreadLimit>0) - maxnumberofthreadsforwavelet = min(max(options.rgbDenoiseThreadLimit / 2, 1), maxnumberofthreadsforwavelet); - - numthreads = MIN(numtiles,omp_get_max_threads()); - if(maxnumberofthreadsforwavelet > 0) - numthreads = MIN(numthreads,maxnumberofthreadsforwavelet); -#ifdef _RT_NESTED_OPENMP - wavNestedLevels = omp_get_max_threads() / numthreads; - bool oldNested = omp_get_nested(); - if(wavNestedLevels < 2) - wavNestedLevels = 1; - else - omp_set_nested(true); - if(maxnumberofthreadsforwavelet > 0) - while(wavNestedLevels*numthreads > maxnumberofthreadsforwavelet) - wavNestedLevels--; -#endif - if(settings->verbose) - printf("Ip Wavelet uses %d main thread(s) and up to %d nested thread(s) for each main thread\n",numthreads,wavNestedLevels); - - -#endif - -#ifdef _OPENMP -#pragma omp parallel num_threads(numthreads) -#endif -{ - float *mean = new float [9]; - float *meanN = new float [9]; - float *sigma = new float [9]; - float *sigmaN = new float [9]; - float *MaxP = new float [9]; - float *MaxN = new float [9]; - - float** varhue = new float*[tileheight]; - for (int i=0; i we can use output buffer for labco - labco = dst; - if(cp.avoi) { // we need a buffer to hold a copy of the L channel - Lold = new float*[tileheight]; - LoldBuffer = new float[tilewidth*tileheight]; - memcpy(LoldBuffer, lab->L[0], tilewidth*tileheight*sizeof(float)); - for (int i=0; iL; - } - -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(wavNestedLevels) if(wavNestedLevels>1) -#endif - - for (int i=tiletop; ia[i][j]); - bv = LVFU(lab->b[i][j]); - huev = xatan2f(bv,av); - chrov = _mm_sqrt_ps(SQRV(av)+SQRV(bv)) / c327d68v; - _mm_storeu_ps(&varhue[i1][j1],huev); - _mm_storeu_ps(&varchro[i1][j1], chrov); - if(labco != lab) { - _mm_storeu_ps(&(labco->L[i1][j1]),LVFU(lab->L[i][j])); - _mm_storeu_ps(&(labco->a[i1][j1]),av); - _mm_storeu_ps(&(labco->b[i1][j1]),bv); - } - } -#else - j=tileleft; -#endif - for (; ja[i][j]; - float b=lab->b[i][j]; - varhue[i1][j1]=xatan2f(b,a); - varchro[i1][j1]=(sqrtf(a*a+b*b))/327.68f; - if(labco != lab) { - labco->L[i1][j1] = lab->L[i][j]; - labco->a[i1][j1] = a; - labco->b[i1][j1] = b; - } - } - } - //to avoid artifacts in blue sky - if(params->wavelet.median) { - float** tmL; - int wid=labco->W; - int hei=labco->H; - int borderL = 1; - tmL = new float*[hei]; - for (int i=0; iL[i][j]; - } - } - -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for num_threads(wavNestedLevels) if(wavNestedLevels>1) -#endif - for (int i=1; i - 2.5f) && (varchro[i][j] > 15.f && varchro[i][j] < 55.f) && labco->L[i][j] > 6000.f) //blue sky + med3x3 ==> after for more effect use denoise - med3(labco->L[i][j] ,labco->L[i-1][j], labco->L[i+1][j] ,labco->L[i][j+1],labco->L[i][j-1], labco->L[i-1][j-1],labco->L[i-1][j+1],labco->L[i+1][j-1],labco->L[i+1][j+1],tmL[i][j]);//3x3 - } - } - for(int i = borderL; i < hei-borderL; i++ ) { - for(int j = borderL; j < wid-borderL; j++) { - labco->L[i][j] = tmL[i][j]; - } - } - - for (int i=0; iW * labco->H; - - int levwavL = levwav; - bool ref0=false; - if((cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f || cp.lev3s > 0.f) && cp.noiseena) ref0=true; - - // printf("LevwavL before: %d\n",levwavL); - if(cp.contrast == 0.f && cp.tonemap==false && cp.conres == 0.f && cp.conresH == 0.f && cp.val ==0 && !ref0 && params->wavelet.CLmethod=="all") { // no processing of residual L or edge=> we probably can reduce the number of levels - while(levwavL > 0 && cp.mul[levwavL-1] == 0.f) // cp.mul[level] == 0.f means no changes to level - levwavL--; - } - // printf("LevwavL after: %d\n",levwavL); - // if(cp.noiseena){ - if(levwavL < 4 ) levwavL=4;//to allow edge => I always allocate 3 (4) levels..because if user select wavelet it is to do something !! - // } - // else { - // if(levwavL < 3) levwavL=3;//to allow edge => I always allocate 3 (4) levels..because if user select wavelet it is to do something !! - // } - if(levwavL > 0) { - wavelet_decomposition* Ldecomp = new wavelet_decomposition (labco->data, labco->W, labco->H, levwavL, 1, skip, max(1,wavNestedLevels), DaubLen ); - if(!Ldecomp->memoryAllocationFailed) { - - float madL[8][3]; - bool memoryAllocationFailed = false; -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for schedule(dynamic) collapse(2) num_threads(wavNestedLevels) if(wavNestedLevels>1) -#endif - for (int lvl=0; lvl<4; lvl++) { - for (int dir=1; dir<4; dir++) { - int Wlvl_L = Ldecomp->level_W(lvl); - int Hlvl_L = Ldecomp->level_H(lvl); - - float ** WavCoeffs_L = Ldecomp->level_coeffs(lvl); - - madL[lvl][dir-1] = SQR(Mad(WavCoeffs_L[dir], Wlvl_L*Hlvl_L)); - } - } - int ind=0; - bool ref=false; - if((cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f || cp.lev3s > 0.f) && cp.noiseena) ref=true; - bool contr=false; - for(int f=0;f 0 || ref || contr) {//edge - Evaluate2(*Ldecomp, cp, ind, mean, meanN, sigma, sigmaN, MaxP, MaxN, madL); - } - //init for edge and denoise - float vari[4]; - - vari[0]=8.f*SQR((cp.lev0n/125.0)*(1.0+ cp.lev0n/25.0)); - vari[1]=8.f*SQR((cp.lev1n/125.0)*(1.0+ cp.lev1n/25.0)); - vari[2]=8.f*SQR((cp.lev2n/125.0)*(1.0+ cp.lev2n/25.0)); - vari[3]=8.f*SQR((cp.lev3n/125.0)*(1.0+ cp.lev3n/25.0)); - int edge=1; - if((cp.lev0n > 0.1f || cp.lev1n > 0.1f || cp.lev2n > 0.1f || cp.lev3n > 0.1f) && cp.noiseena) { - vari[0] = max(0.0001f,vari[0]); - vari[1] = max(0.0001f,vari[1]); - vari[2] = max(0.0001f,vari[2]); - vari[3] = max(0.0001f,vari[3]); - float* noisevarlum = NULL; // we need a dummy to pass it to WaveletDenoiseAllL - if(!WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, vari, edge))// - memoryAllocationFailed = true; - } - ind=1; - //Flat curve for Contrast=f(H) in levels - FlatCurve* ChCurve = NULL;//curve C=f(H) - bool Chutili = false; - ChCurve = new FlatCurve(params->wavelet.Chcurve); - if (!ChCurve || ChCurve->isIdentity()) { - if (ChCurve) { - delete ChCurve; - ChCurve = NULL; - } - } else - Chutili = true; - - - WaveletcontAllL(labco, varhue, varchro, *Ldecomp, cp, skip, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, waOpacityCurveWL, ChCurve, Chutili); - if(cp.val > 0 || ref || contr || cp.diagcurv) {//edge - Evaluate2(*Ldecomp, cp, ind, mean, meanN, sigma, sigmaN, MaxP, MaxN, madL); - } - WaveletcontAllLfinal(labco, varhue, varchro, *Ldecomp, cp, skip, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavCLVCcurve, waOpacityCurveWL, ChCurve, Chutili); - //Evaluate2(*Ldecomp, cp, ind, mean, meanN, sigma, sigmaN, MaxP, MaxN, madL); - - Ldecomp->reconstruct(labco->data, cp.strength); - } - delete Ldecomp; - } - //Flat curve for H=f(H) in residual image - FlatCurve* hhCurve = NULL;//curve H=f(H) - bool hhutili = false; - hhCurve = new FlatCurve(params->wavelet.hhcurve); - if (!hhCurve || hhCurve->isIdentity()) { - if (hhCurve) { - delete hhCurve; - hhCurve = NULL; - } - } else - hhutili = true; - - - if(!hhutili) {//always a or b - int levwava = levwav; - // printf("Levwava before: %d\n",levwava); - if(cp.chrores == 0.f && params->wavelet.CLmethod=="all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels - while(levwava > 0 && !cp.diag &&(((cp.CHmet==2 && (cp.chro == 0.f || cp.mul[levwava-1] == 0.f )) || (cp.CHmet!=2 && (levwava == 10 || (!cp.curv || (cp.curv && cp.mulC[levwava-1] == 0.f)))))) && (!cp.opaRG || levwava == 10 || (cp.opaRG && cp.mulopaRG[levwava-1] == 0.f)) && ((levwava == 10 ||(cp.CHSLmet==1 && cp.mulC[levwava-1] == 0.f)))) { - levwava--; - } - } - //printf("Levwava after: %d\n",levwava); - if(levwava > 0) { - wavelet_decomposition* adecomp = new wavelet_decomposition (labco->data+datalen, labco->W, labco->H,levwava, 1, skip, max(1,wavNestedLevels), DaubLen ); - if(!adecomp->memoryAllocationFailed) { - WaveletcontAllAB(labco, varhue, varchro, *adecomp, waOpacityCurveW, cp, true); - adecomp->reconstruct(labco->data+datalen, cp.strength); - } - delete adecomp; - } - int levwavb = levwav; - //printf("Levwavb before: %d\n",levwavb); - if(cp.chrores == 0.f && params->wavelet.CLmethod=="all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels - while(levwavb > 0 && !cp.diag && (((cp.CHmet==2 && (cp.chro == 0.f || cp.mul[levwavb-1] == 0.f )) || (cp.CHmet!=2 && (levwavb == 10 || (!cp.curv || (cp.curv && cp.mulC[levwavb-1] == 0.f)))))) && (!cp.opaBY || levwavb == 10 || (cp.opaBY && cp.mulopaBY[levwavb-1] == 0.f)) && ((levwavb == 10 ||(cp.CHSLmet==1 && cp.mulC[levwavb-1] == 0.f)))) { - levwavb--; - } - } - // printf("Levwavb after: %d\n",levwavb); - if(levwavb > 0) { - wavelet_decomposition* bdecomp = new wavelet_decomposition (labco->data+2*datalen, labco->W, labco->H, levwavb, 1, skip, max(1,wavNestedLevels), DaubLen ); - if(!bdecomp->memoryAllocationFailed) { - WaveletcontAllAB(labco, varhue, varchro, *bdecomp, waOpacityCurveW, cp, false); - bdecomp->reconstruct(labco->data+2*datalen, cp.strength); - } - delete bdecomp; - } - } else {// a and b - int levwavab = levwav; - // printf("Levwavab before: %d\n",levwavab); - if(cp.chrores == 0.f && !hhutili && params->wavelet.CLmethod=="all") { // no processing of residual ab => we probably can reduce the number of levels - while(levwavab > 0 && (((cp.CHmet==2 && (cp.chro == 0.f || cp.mul[levwavab-1] == 0.f )) || (cp.CHmet!=2 && (levwavab == 10 || (!cp.curv || (cp.curv && cp.mulC[levwavab-1] == 0.f)))))) && (!cp.opaRG || levwavab == 10 || (cp.opaRG && cp.mulopaRG[levwavab-1] == 0.f)) && ((levwavab == 10 ||(cp.CHSLmet==1 && cp.mulC[levwavab-1] == 0.f)))) { - levwavab--; - } - } - // printf("Levwavab after: %d\n",levwavab); - if(levwavab > 0) { - wavelet_decomposition* adecomp = new wavelet_decomposition (labco->data+datalen, labco->W, labco->H,levwavab, 1, skip, max(1,wavNestedLevels), DaubLen ); - wavelet_decomposition* bdecomp = new wavelet_decomposition (labco->data+2*datalen, labco->W, labco->H, levwavab, 1, skip, max(1,wavNestedLevels), DaubLen ); - if(!adecomp->memoryAllocationFailed && !bdecomp->memoryAllocationFailed) { - WaveletcontAllAB(labco, varhue, varchro, *adecomp, waOpacityCurveW, cp, true); - WaveletcontAllAB(labco, varhue, varchro, *bdecomp, waOpacityCurveW, cp, false); - WaveletAandBAllAB(labco, varhue, varchro, *adecomp, *bdecomp, cp, waOpacityCurveW, hhCurve, hhutili ); - - adecomp->reconstruct(labco->data+datalen, cp.strength); - bdecomp->reconstruct(labco->data+2*datalen, cp.strength); - - } - delete adecomp; - delete bdecomp; - } - } - if (hhCurve) - delete hhCurve; - - if(numtiles > 1 || (numtiles == 1 /*&& cp.avoi*/)) {//in all case since I add contrast curve - //calculate mask for feathering output tile overlaps - float Vmask[height+overlap] ALIGNED16; - float Hmask[width+overlap] ALIGNED16; - - if(numtiles > 1) { - for (int i=0; i0) Vmask[i] = mask; - if (tilebottom0) Hmask[i] = mask; - if (tilerighttoneCurve.hrenabled; - -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for schedule(dynamic,16) num_threads(wavNestedLevels) if(wavNestedLevels>1) -#endif - for (int i=tiletop; ia[i1][col]); - bv = LVFU(labco->b[i1][col]); - _mm_store_ps(&atan2Buffer[col],xatan2f(bv,av)); - - cv = _mm_sqrt_ps(SQRV(av)+SQRV(bv)); - yv = av / cv; - xv = bv / cv; - xyMask = vmaskf_eq(zerov, cv); - yv = vself(xyMask, onev, yv); - xv = vself(xyMask, zerov, xv); - _mm_store_ps(&yBuffer[col],yv); - _mm_store_ps(&xBuffer[col],xv); - _mm_store_ps(&chprovBuffer[col], cv / c327d68v); - - } - for(;cola[i1][col]; - float b = labco->b[i1][col]; - atan2Buffer[col] = xatan2f(b,a); - float Chprov1=sqrtf(SQR(a) + SQR(b)); - yBuffer[col] = (Chprov1 == 0.f) ? 1.f : a/Chprov1; - xBuffer[col] = (Chprov1 == 0.f) ? 0.f : b/Chprov1; - chprovBuffer[col] = Chprov1/327.68; - } - } -#endif - - for (int j=tileleft; ja[i1][j1]; - b = labco->b[i1][j1]; - float HH=xatan2f(b,a); - float Chprov1=sqrtf(SQR(a) + SQR(b)); - float2 sincosv; - sincosv.y = (Chprov1==0.0f) ? 1.f : a/(Chprov1); - sincosv.x = (Chprov1==0.0f) ? 0.f : b/(Chprov1); - Chprov1 /= 327.68f; -#endif - L = labco->L[i1][j1]; - const float Lin=labco->L[i1][j1]; - - if(wavclCurve && cp.finena) {labco->L[i1][j1] =(0.5f*Lin + 1.5f*wavclCurve[Lin])/2.f;}//apply contrast curve - L = labco->L[i1][j1]; - - float Lprov1=L/327.68f; - float Lprov2 = Lold[i][j]/327.68f; - float memChprov=varchro[i1][j1]; - float R,G,B; -#ifdef _DEBUG - bool neg=false; - bool more_rgb=false; - Color::gamutLchonly(HH,sincosv, Lprov1,Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); -#else - Color::gamutLchonly(HH,sincosv, Lprov1,Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); -#endif - L=Lprov1*327.68f; - - a=327.68f*Chprov1*sincosv.y;//gamut - b=327.68f*Chprov1*sincosv.x;//gamut - float correctionHue=0.0f; // Munsell's correction - float correctlum=0.0f; - Lprov1=L/327.68f; - float Chprov=sqrtf(SQR(a)+ SQR(b))/327.68f; -#ifdef _DEBUG - Color::AllMunsellLch(true, Lprov1,Lprov2,HH,Chprov,memChprov,correctionHue,correctlum, MunsDebugInfo); -#else - Color::AllMunsellLch(true, Lprov1,Lprov2,HH,Chprov,memChprov,correctionHue,correctlum); -#endif - - if(correctionHue!=0.f || correctlum!=0.f) { // only calculate sin and cos if HH changed - if(fabs(correctionHue) < 0.015f) - HH+=correctlum; // correct only if correct Munsell chroma very little. - sincosv = xsincosf(HH+correctionHue); - } - - a=327.68f*Chprov*sincosv.y;// apply Munsell - b=327.68f*Chprov*sincosv.x;//aply Munsell - } else {//general case - L = labco->L[i1][j1]; - const float Lin=labco->L[i1][j1]; - - if(wavclCurve && cp.finena) {labco->L[i1][j1] = (0.5f*Lin + 1.5f*wavclCurve[Lin])/2.f;}//apply contrast curve - L = labco->L[i1][j1]; - a = labco->a[i1][j1]; - b = labco->b[i1][j1]; - } - if(numtiles > 1) { - float factor = Vmask[i1]*Hmask[j1]; - dsttmp->L[i][j]+= factor*L; - dsttmp->a[i][j]+= factor*a; - dsttmp->b[i][j]+= factor*b; - } else { - dsttmp->L[i][j] = L; - dsttmp->a[i][j] = a; - dsttmp->b[i][j] = b; - - } - } - } - } - if(LoldBuffer != NULL) { - delete [] LoldBuffer; - delete [] Lold; - } - if(numtiles>1) - delete labco; - } - } - for (int i=0; i 1) { - dst->CopyFrom(dsttmp); - delete dsttmp; - } - - if (settings->verbose) { - t2e.set(); - printf("Wavelet performed in %d usec:\n", t2e.etime(t1e)); - } - -}//end o - - - - -#undef TS -#undef fTS -#undef offset -#undef epsilon - - void ImProcFunctions::Aver( float * RESTRICT DataList, int datalen, float &averagePlus, float &averageNeg, float &max, float &min) { - - //find absolute mean - int countP = 0, countN = 0; - float averaP = 0.f, averaN = 0.f; - - float thres = 5.f;//different fom zero to take into account only data large enough - max=0.f; - min=0.f; -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) -#endif -{ - float lmax = 0.f, lmin = 0.f; -#ifdef _RT_NESTED_OPENMP -#pragma omp for reduction(+:averaP,averaN,countP,countN) nowait -#endif - for(int i=0;i= thres) { - averaP += DataList[i]; - if(DataList[i]> lmax) - lmax = DataList[i]; - countP++; - } - else if(DataList[i] < -thres) { - averaN += DataList[i]; - if(DataList[i] < lmin) - lmin = DataList[i]; - countN++; - } - } -#ifdef _RT_NESTED_OPENMP -#pragma omp critical -#endif -{ - max = max > lmax ? max : lmax; - min = min < lmin ? min : lmin; -} -} - - averagePlus=averaP/countP; - averageNeg=averaN/countN; - - } - - - void ImProcFunctions::Sigma( float * RESTRICT DataList, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg) { - int countP = 0, countN = 0; - float variP = 0.f, variN = 0.f; - float thres = 5.f;//different fom zero to take into account only data large enough - -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for reduction(+:variP,variN,countP,countN) num_threads(wavNestedLevels) if(wavNestedLevels>1) -#endif - for(int i=0;i= thres) { - variP += SQR(DataList[i] - averagePlus); - countP++; - } - else if(DataList[i] <= -thres) { - variN += SQR(DataList[i] - averageNeg); - countN++; - } - } - - sigmaPlus=sqrt(variP/countP); - sigmaNeg=sqrt(variN/countN); - - } - - void ImProcFunctions::Evaluate2(wavelet_decomposition &WaveletCoeffs_L, - struct cont_params cp, int ind, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, float madL[8][3]){ -//StopWatch Stop1("Evaluate2"); - int maxlvl = WaveletCoeffs_L.maxlevel(); - for (int lvl=0; lvlwavelet.thres; - for (int dir=1; dir<4; dir++) { - Aver(WavCoeffs_L[dir], W_L*H_L, avLP[dir], avLN[dir], maxL[dir], minL[dir]); - Sigma(WavCoeffs_L[dir], W_L*H_L, avLP[dir], avLN[dir], sigP[dir], sigN[dir]); - // printf("dir=%d level=%d avLP=%f max=%f avLN=%f min=%f sigP=%f sigN=%f\n",dir,level,avLP[dir] ,maxL[dir], avLN[dir] ,minL[dir], sigP[dir], sigN[dir]); - } - AvL=0.f;AvN=0.f;SL=0.f;SN=0.f;maxLP=0.f;maxLN=0.f;MADL=0.f; - for (int dir=1; dir<4; dir++) { - AvL +=avLP[dir]; - AvN +=avLN[dir]; - SL +=sigP[dir]; - SN +=sigN[dir]; - maxLP += maxL[dir]; - maxLN += minL[dir]; - MADL += madL[dir]; - } - AvL/=3; - AvN/=3; - SL/=3; - SN/=3; - maxLP/=3; - maxLN/=3; - MADL/=3; - if(level < 4) MADL=sqrt(MADL);else MADL=0.f; - mean[level]=AvL; - meanN[level]=AvN; - sigma[level]=SL; - sigmaN[level]=SN; - MaxP[level]=maxLP; - MaxN[level]=maxLN; - // if(params->wavelet.CLmethod!="all") {//display only if user choose different from all - // printf("Ind=%d Level=%d MadL=%f AvL=%f AvN=%f SL=%f SN=%f maxP=%f maxN=%f\n",ind, level,MADL,mean[level],meanN[level],sigma[level],sigmaN[level],MaxP[level],MaxN[level]); - // } - } - -float *ImProcFunctions::ContrastDR(float *Source, int skip, struct cont_params &cp, int W_L, int H_L, float Compression,float DetailBoost,float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx, float *Contrast){ - int n=W_L*H_L; - if(Contrast == NULL) Contrast = new float[n]; - memcpy(Contrast, Source, n*sizeof(float)); -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for -#endif - for (int i=0; i ave) { - float kh = ah*(Source[i]*100.f)+bh; - prov=32768.f*Source[i]; - Contrast[i]=ave+kh*(Source[i]*32768.f-ave); - } else { - float kl = al*(Source[i]*100.f)+bl; - prov=32768.f*Source[i]; - Contrast[i]=ave-kl*(ave-Source[i]*32768.f); - } - float diflc=Contrast[i]-prov; - diflc*=factorx; - Contrast[i] = (prov + diflc)/32768.f; - //contrast between 0 and 1 - } -*/ - Contrast[i] = Source[i] ; - - } - return Contrast; -} - -SSEFUNCTION float *ImProcFunctions::CompressDR(float *Source, int skip, struct cont_params &cp, int W_L, int H_L, float Compression,float DetailBoost,float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx, float *Compressed){ - - const float eps = 0.000001f; - int n=W_L*H_L; - -#ifdef __SSE2__ -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel -#endif -{ - __m128 epsv = _mm_set1_ps( eps ); -#ifdef _RT_NESTED_OPENMP -#pragma omp for -#endif - for(int ii = 0; ii < n-3; ii+=4) - _mm_storeu_ps( &Source[ii], xlogf(LVFU(Source[ii]) + epsv)); -} - for(int ii = n-(n%4); ii < n; ii++) - Source[ii] = xlogf(Source[ii] + eps); - -#else -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for -#endif - for(int ii = 0; ii < n; ii++) - Source[ii] = xlogf(Source[ii] + eps); -#endif - - float *ucr =ContrastDR(Source, skip, cp, W_L, H_L, Compression,DetailBoost,max0, min0, ave, ah, bh, al, bl, factorx); - if(Compressed == NULL) Compressed = ucr; - float temp; - if(DetailBoost>0.f && DetailBoost < 0.05f ) { - float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2) - temp = 1.2f*xlogf( -betemp); - temp /= 20.f; - } - else if(DetailBoost>=0.05f && DetailBoost < 0.25f ) { - float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2) - temp = 1.2f*xlogf( -betemp); - temp /= (-75.f*DetailBoost+23.75f); - } - else if(DetailBoost>=0.25f) { - float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2) - temp = 1.2f*xlogf( -betemp); - temp /= (-2.f*DetailBoost + 5.5f); - } - - else temp= (Compression - 1.0f)/20.f; -// printf("temp=%f \n", temp); - - -#ifdef __SSE2__ -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel -#endif -{ - __m128 cev, uev, sourcev; - __m128 epsv = _mm_set1_ps( eps ); - __m128 DetailBoostv = _mm_set1_ps( DetailBoost ); - __m128 tempv = _mm_set1_ps( temp ); -#ifdef _RT_NESTED_OPENMP -#pragma omp for -#endif - for(int i = 0; i < n-3; i+=4){ - cev = xexpf(LVFU(Source[i]) + LVFU(ucr[i])*(tempv)) - epsv; - uev = xexpf(LVFU(ucr[i])) - epsv; - sourcev = xexpf(LVFU(Source[i])) - epsv; - _mm_storeu_ps( &Source[i], sourcev); - _mm_storeu_ps( &Compressed[i], cev + DetailBoostv * (sourcev - uev) ); - } -} - for(int i=n-(n%4); i < n; i++){ - float ce = xexpf(Source[i] + ucr[i]*(temp)) - eps; - float ue = xexpf(ucr[i]) - eps; - Source[i] = xexpf(Source[i]) - eps; - Compressed[i] = ce + DetailBoost*(Source[i] - ue); - } - -#else -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for -#endif - for(int i = 0; i < n; i++){ - float ce = xexpf(Source[i] + ucr[i]*(temp)) - eps; - float ue = xexpf(ucr[i]) - eps; - Source[i] = xexpf(Source[i]) - eps; - Compressed[i] = ce + DetailBoost*(Source[i] - ue); - } -#endif - - if(Compressed != ucr) delete[] ucr; - return Compressed; - - -} - -void ImProcFunctions::ContrastResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, struct cont_params &cp, int W_L, int H_L, float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx) { - float stren=cp.tmstrength; - float gamm=params->wavelet.gamma; - cp.TMmeth=2;//default after testing - if(cp.TMmeth ==1) {min0 = 0.0f;max0=32768.f;} - else if (cp.TMmeth ==2) {min0 = 0.0f;} -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for -#endif - for(int i = 0; i < W_L*H_L; i++) - { WavCoeffs_L0[i]= (WavCoeffs_L0[i] - min0)/max0; - WavCoeffs_L0[i]*=gamm; - } - - float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. - float DetailBoost = stren; - if(stren < 0.0f) DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing. - - - CompressDR(WavCoeffs_L0, skip, cp, W_L, H_L, Compression,DetailBoost,max0, min0, ave, ah, bh, al, bl, factorx, WavCoeffs_L0); - - -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for // removed schedule(dynamic,10) -#endif - for(int ii = 0; ii < W_L*H_L; ii++) - WavCoeffs_L0[ii] = WavCoeffs_L0[ii]*max0*(1.f/gamm) + min0; - } - - - - - void ImProcFunctions::EPDToneMapResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, struct cont_params cp, int W_L, int H_L, float max0, float min0) { - - - float stren=cp.tmstrength; - float edgest=params->epd.edgeStopping; - float sca=params->epd.scale; - float gamm=params->wavelet.gamma; - float rew=params->epd.reweightingIterates; - EdgePreservingDecomposition epd2 = EdgePreservingDecomposition(W_L, H_L); - cp.TMmeth=2;//default after testing - if(cp.TMmeth ==1) {min0 = 0.0f;max0=32768.f;} - else if (cp.TMmeth ==2) {min0 = 0.0f;} - // max0=32768.f; -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for -#endif - for(int i = 0; i < W_L*H_L; i++) - { WavCoeffs_L0[i]= (WavCoeffs_L0[i] - min0)/max0; - WavCoeffs_L0[i]*=gamm; - } - - float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. - float DetailBoost = stren; - if(stren < 0.0f) DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing. - - //Auto select number of iterates. Note that p->EdgeStopping = 0 makes a Gaussian blur. - if(Iterates == 0) Iterates = (unsigned int)(edgest*15.0f); - - - epd2.CompressDynamicRange(WavCoeffs_L0, (float)sca/skip, edgest, Compression, DetailBoost, Iterates, rew, WavCoeffs_L0); - - //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel for // removed schedule(dynamic,10) -#endif - for(int ii = 0; ii < W_L*H_L; ii++) - WavCoeffs_L0[ii] = WavCoeffs_L0[ii]*max0*(1.f/gamm) + min0; - } - -void ImProcFunctions::WaveletcontAllLfinal(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_L, - struct cont_params &cp, int skip, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveWL & waOpacityCurveWL, FlatCurve* ChCurve, bool Chutili){ - - int maxlvl = WaveletCoeffs_L.maxlevel(); - int W_L = WaveletCoeffs_L.level_W(0); - int H_L = WaveletCoeffs_L.level_H(0); - float * WavCoeffs_L0 = WaveletCoeffs_L.coeff0; - - -#ifdef _RT_NESTED_OPENMP -#pragma omp for schedule(dynamic) collapse(2) -#endif - for (int dir=1; dir<4; dir++) { - for (int lvl=0; lvl1) -#endif - for (int i=0; i1) -#endif -{ - float lminL = FLT_MAX; - float lmaxL = 0.f; - -#ifdef _RT_NESTED_OPENMP -#pragma omp for -#endif - for(int i = 0; i < W_L*H_L; i++) { - if(WavCoeffs_L0[i] < lminL) lminL = WavCoeffs_L0[i]; - if(WavCoeffs_L0[i] > lmaxL) lmaxL = WavCoeffs_L0[i]; - - } -#ifdef _RT_NESTED_OPENMP -#pragma omp critical -#endif - { if(lminL < min0) min0 = lminL; - if(lmaxL > max0) max0 = lmaxL; - } - -} - - } - - // printf("MAXmax0=%f MINmin0=%f\n",max0,min0); - -//tone mapping -if(cp.tonemap && cp.contmet==2 && cp.resena) { - //iterate = 5 - EPDToneMapResid(WavCoeffs_L0, 5, skip, cp, W_L, H_L, max0, min0); - -} -//end tonemapping - - - max0/=327.68f; - min0/=327.68f; - float ave = avedbl / (double)(W_L*H_L); - float av=ave/327.68f; - float ah=(multH-1.f)/(av-max0);// - float bh=1.f-max0*ah; - float al=(multL-1.f)/(av-min0); - float bl=1.f-min0*al; - float factorx=1.f; -// float *koeLi[9]; -// float maxkoeLi[9]; - float *koeLi[12]; - float maxkoeLi[12]; - - float *koeLibuffer = NULL; - bool lipschitz =false; - lipschitz=true; - - if(lipschitz==true) { - for(int y=0;y<12;y++) maxkoeLi[y]=0.f;//9 - koeLibuffer = new float[12*H_L*W_L];//12 - for (int i=0; i<12; i++) {//9 - koeLi[i] = &koeLibuffer[i*W_L*H_L]; - } - - for(int j=0;j<12;j++)//9 - for (int i=0; i1) -#endif -{ - if(contrast != 0.f && cp.resena) { // contrast = 0.f means that all will be multiplied by 1.f, so we can skip this step - { -#ifdef _RT_NESTED_OPENMP -#pragma omp for -#endif - for (int i=0; i ave) { - float kh = ah*(WavCoeffs_L0[i]/327.68f)+bh; - prov=WavCoeffs_L0[i]; - WavCoeffs_L0[i]=ave+kh*(WavCoeffs_L0[i]-ave); - } else { - float kl = al*(WavCoeffs_L0[i]/327.68f)+bl; - prov=WavCoeffs_L0[i]; - WavCoeffs_L0[i]=ave-kl*(ave-WavCoeffs_L0[i]); - } - float diflc=WavCoeffs_L0[i]-prov; - diflc*=factorx; - WavCoeffs_L0[i] = prov + diflc; - } - } - } - } - -if(cp.tonemap && cp.contmet==1 && cp.resena) { - float maxp=max0*256.f; - float minp=min0*256.f; -#ifdef _RT_NESTED_OPENMP -#pragma omp single -#endif - ContrastResid(WavCoeffs_L0, 5, skip, cp, W_L, H_L, maxp, minp, ave, ah, bh, al, bl, factorx ); -} -#ifdef _RT_NESTED_OPENMP -#pragma omp barrier -#endif - - if((cp.conres != 0.f || cp.conresH != 0.f) && cp.resena) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step -#ifdef _RT_NESTED_OPENMP -#pragma omp for nowait -#endif - for (int i=0; i (100.f-tran)) - tran=100.f-cp.th; - if(LL100 < cp.th){ - float aalp=(1.f-alp)/cp.th;//no changes for LL100 = cp.th - float kk=aalp*LL100+alp; - WavCoeffs_L0[i] *= (1.f+kk*cp.conres/200.f); - } - else if(LL100 < cp.th + tran) { - float ath = -cp.conres/tran; - float bth = cp.conres-ath*cp.th; - WavCoeffs_L0[i] *= (1.f+(LL100*ath+bth)/200.f); - } - //highlight - tran=5.f; - if(cp.thH < (tran)) - tran = cp.thH; - if(LL100 > cp.thH) - WavCoeffs_L0[i] *= (1.f+cp.conresH/200.f); - else if(LL100 > (cp.thH - tran)) { - float athH = cp.conresH/tran; - float bthH = cp.conresH-athH*cp.thH; - WavCoeffs_L0[i] *= (1.f+(LL100*athH+bthH)/200.f); - } - } - } - //enabled Lipschitz..replace simple by complex edge detection - // I found this concept on the web (doctoral thesis on medical Imaging) - // I was inspired by the principle of Canny and Lipschitz (continuity and derivability) - // I adapted the principle but have profoundly changed the algorithm - // One can 1) change all parameters and found good parameters; - //one can also chnage in calckoe - float edd=settings->ed_detec; - float eddlow=settings->ed_low;//5 to 40 - // float eddlipinfl=settings->ed_lipinfl; - // float eddlipampl=settings->ed_lipampl; - float eddlipinfl=0.005f*cp.edgsens + 0.4f; - float eddlipampl=1.f + cp.edgampl/50.f; - // float eddlow=5.f + cp.edgampl/2.f;//settings->ed_low;//5 to 40 - - -if(cp.detectedge && lipschitz==true) { //enabled Lipschitz control...more memory..more time... - float *tmCBuffer = new float[H_L*W_L]; - float *tmC[H_L]; - for (int i=0; i 1 for alp >eddlipinfl and alph < 1 - //Liamp < 1 for alp < eddlipinfl and alph > 0 - if(alph > 1.f) {alph = 1.f/ alph;} - if(beta > 1.f) {beta=1.f/beta;} - //take into account diagonal - //if in same value OK - //if not no edge or reduction - float bet=1.f; - //if(cp.lip3) {//enhance algorithm - if(alph > eddlipinfl && beta < 0.85f*eddlipinfl) {//0.85 arbitrary value ==> eliminate from edge if H V D too different - bet=beta; - } - //} - float AmpLip=1.f; - - if(alph > eddlipinfl) {AmpLip=alipinfl*alph+blipinfl;kampli=SQR(bet)*AmpLip*aamp;}//If beta low reduce kampli - else {AmpLip=(1.f/eddlipinfl)*SQR(SQR(alph*bet));kampli=AmpLip/aamp;}//Strong Reduce if beta low - // comparaison betwwen pixel and neighbours to do ==> I think 3 dir above is better - /* if(cp.lip3){ - koeLi[lvl*3][i*W_L + j] = (koeLi[lvl*3][i*W_L + j] + koeLi[lvl*3][(i-1)*W_L + j] + koeLi[lvl*3][(i+1)*W_L + j] - + koeLi[lvl*3][i*W_L + j+1] + koeLi[lvl*3][i*W_L + j-1] + koeLi[lvl*3][(i-1)*W_L + j-1] - + koeLi[lvl*3][(i-1)*W_L + j+1] +koeLi[lvl*3][(i+1)*W_L + j-1] +koeLi[lvl*3][(i+1)*W_L + j+1])/9.f; - } - */ - // apply to each direction Wavelet level : horizontal / vertiacle / diagonal - //interm += SQR(koeLi[lvl*3 + dir-1][i*W_L + j]); - - interm*=kampli; - if(interm < cp.eddetthr/eddlow) interm = 0.01f;//eliminate too low values - //we can change this part of algo==> not equal but ponderate - koeLi[lvl*3][i*W_L + j]=koeLi[lvl*3 + 1][i*W_L + j]=koeLi[lvl*3 + 2][i*W_L + j]=interm;//new value - //here KoeLi contains values where gradient is high and coef high, and eliminate low values... - } - } - } - // end -} - -#ifdef _RT_NESTED_OPENMP -#pragma omp for schedule(dynamic) collapse(2) -#endif - for (int dir=1; dir<4; dir++) { - for (int lvl=0; lvl1) -#endif -{ -#ifdef __SSE2__ - float huebuffer[W_L] ALIGNED64; - float chrbuffer[W_L] ALIGNED64; -#endif // __SSE2__ -#ifdef _RT_NESTED_OPENMP -#pragma omp for schedule(dynamic,16) -#endif - for (int i=0; iv(i,j) = valpar; - } - */ - float valparam = float((hhCurve->getVal(Color::huelab_to_huehsv2(hueR))-0.5f) * 1.7f) +hueR;//get H=f(H) 1.7 optimisation ! - float2 sincosval = xsincosf(valparam); - WavCoeffs_a0[i*W_L+j]=chR*sincosval.y; - WavCoeffs_b0[i*W_L+j]=chR*sincosval.x; - } - } -} - } - -} - - void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_ab,const WavOpacityCurveW & waOpacityCurveW, - struct cont_params &cp, const bool useChannelA){ - - int maxlvl = WaveletCoeffs_ab.maxlevel(); - int W_L = WaveletCoeffs_ab.level_W(0); - int H_L = WaveletCoeffs_ab.level_H(0); - - float * WavCoeffs_ab0 = WaveletCoeffs_ab.coeff0; - -#ifdef _RT_NESTED_OPENMP -#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) -#endif -{ - if(cp.chrores != 0.f && cp.resena) { // cp.chrores == 0.f means all will be multiplied by 1.f, so we can skip the processing of residual - -#ifdef _RT_NESTED_OPENMP -#pragma omp for nowait -#endif - for (int i=0; i 0.f){ - if((modhue < cp.t_ry && modhue > cp.t_ly)) { - scale=(100.f-cp.sky)/100.1f; - } else if((modhue >= cp.t_ry && modhue < cp.b_ry)) { - scale=(100.f-cp.sky)/100.1f; - float ar=(scale-1.f)/(cp.t_ry- cp.b_ry); - float br=scale-cp.t_ry*ar; - scale=ar*modhue+br; - } else if((modhue > cp.b_ly && modhue < cp.t_ly)) { - scale=(100.f-cp.sky)/100.1f; - float al=(scale-1.f)/(-cp.b_ly + cp.t_ly); - float bl=scale-cp.t_ly*al; - scale=al*modhue+bl; - } - } else if(skyprot < 0.f){ - if((modhue > cp.t_ry || modhue < cp.t_ly)){ - scale=(100.f+cp.sky)/100.1f; - } - /* else if((modhue >= cp.t_ry && modhue < cp.b_ry)) { - scale=(100.f+cp.sky)/100.1f; - float ar=(scale-1.f)/(cp.t_ry- cp.b_ry); - float br=scale-cp.t_ry*ar; - scale=ar*modhue+br; - } - else if((modhue > cp.b_ly && modhue < cp.t_ly)) { - scale=(100.f+cp.sky)/100.1f; - float al=(scale-1.f)/(-cp.b_ly + cp.t_ly); - float bl=scale-cp.t_ly*al; - scale=al*modhue+bl; - } - */ - } - WavCoeffs_ab0[i]*=(1.f+cp.chrores*(scale)/100.f); - - } - } - - if(cp.cbena && cp.resena) {//if user select Toning and color balance - -#ifdef _RT_NESTED_OPENMP -#pragma omp for nowait -#endif - for (int i=0; iL[ii*2][jj*2])/327.68f;//I use labco but I can use also WavCoeffs_L0 (more exact but more memory) - - float sca=1.f;//amplifer - reducter...about 1, but perhaps 0.6 or 1.3 - if(useChannelA) {//green red (little magenta) - //transition to avoid artifacts with 6 between 30 to 36 and 63 to 69 - float aa=(cp.grmed-cp.grlow)/6.f; - float bb= cp.grlow-30.f*aa; - float aaa=(cp.grhigh-cp.grmed)/6.f; - float bbb= cp.grmed-63.f*aaa; - - if(LL < 30.f)//shadows - WavCoeffs_ab0[i]+=cp.grlow*(sca)*300.f; - else if(LL >= 30.f && LL < 36.f) {//transition - float tr=aa*LL+bb; - WavCoeffs_ab0[i]+= tr*(sca)*300.f; - } - else if(LL >= 36.f && LL < 63.f)//midtones - WavCoeffs_ab0[i]+=cp.grmed*(sca)*300.f; - else if(LL >= 63.f && LL < 69.f) {//transition - float trh=aaa*LL+bbb; - WavCoeffs_ab0[i]+=trh*(sca)*300.f; - } - else if(LL >= 69.f)//highlights - WavCoeffs_ab0[i]+=cp.grhigh*(sca)*300.f; - } - else {//blue yellow - //transition with 6 between 30 to 36 and 63 to 69 - float aa1=(cp.blmed-cp.bllow)/6.f; - float bb1= cp.bllow-30.f*aa1; - float aaa1=(cp.blhigh-cp.blmed)/6.f; - float bbb1= cp.blmed-63.f*aaa1; - - if(LL < 30.f) - WavCoeffs_ab0[i]+=cp.bllow*(sca)*300.f; - else if(LL >= 30.f && LL < 36.f) { - float tr1=aa1*LL+bb1; - WavCoeffs_ab0[i]+=tr1*(sca)*300.f; - } - else if(LL >= 36.f && LL < 63.f) - WavCoeffs_ab0[i]+=cp.blmed*(sca)*300.f; - else if(LL >= 63.f && LL < 69.f) { - float trh1=aaa1*LL+bbb1; - WavCoeffs_ab0[i]+=trh1*(sca)*300.f; - } - else if(LL >= 69.f) - WavCoeffs_ab0[i]+=cp.blhigh*(sca)*300.f; - } - } - } - -#ifdef _RT_NESTED_OPENMP -#pragma omp for schedule(dynamic) collapse(2) -#endif - for (int dir=1; dir<4; dir++) { - for (int lvl=0; lvl= 30.f && cp.eddetthr < 50.f) { - borderL = 1; - - for (int i=1; i= 50.f && cp.eddetthr < 75.f) { - borderL = 1; - for (int i=1; i= 75.f) { - borderL = 2; - //if(cp.lip3 && level > 1) { - if(level > 1) {// do not activate 5x5 if level 0 or 1 - - for (int i=2; i lees good results==> probably because structure data different and also I compare to original value which have + and - - for(int i = borderL; i < H_L-borderL; i++ ) {//[-1 0 1] x==>j - for(int j = borderL; j < W_L-borderL; j++) { - tmC[i][j]=- WavCoeffs_LL[dir][(i)*W_L + j-1] + WavCoeffs_LL[dir][(i)*W_L + j+1]; - } - } - for(int i = borderL; i < H_L-borderL; i++ ) {//[1 0 -1] y==>i - for(int j = borderL; j < W_L-borderL; j++) { - tmC[i][j]= - WavCoeffs_LL[dir][(i-1)*W_L + j] + WavCoeffs_LL[dir][(i+1)*W_L + j]; - } - } - */ - - float thr=40.f;//avoid artifact eg. noise...to test - float thr2=1.5f*edd;//edd can be modified in option ed_detect - thr2+=cp.eddet/30.f;//to test - float diffFactor = (cp.eddet/100.f); - for(int i = 0; i < H_L; i++ ) { - for(int j = 0; j < W_L; j++) { - koeLi[level*3 + dir-1][i*W_L + j]=1.f; - } - } - for(int i = borderL; i < H_L-borderL; i++ ) { - for(int j = borderL; j < W_L-borderL; j++) { - // my own algo : probably a little false, but simpler as Lipschitz ! - // Thr2 = maximum of the function ==> Lipsitch says = probably edge -// float temp = WavCoeffs_LL[dir][i*W_L + j]; -// if(temp>=0.f && temp < thr) temp = thr; -// if(temp < 0.f && temp > -thr) temp = -thr; - float temp = max(fabsf(WavCoeffs_LL[dir][i*W_L + j]), thr ); - koeLi[level*3 + dir-1][i*W_L + j]= min(thr2,fabs(tmC[i][j]/temp));// limit maxi - //it will be more complicated to calculate both Wh and Wv, but we have also Wd==> pseudo Lipschitz - if(koeLi[level*3+ dir-1][i*W_L + j] > maxkoeLi[level*3+ dir-1]) - maxkoeLi[level*3+ dir-1] = koeLi[level*3 + dir-1][i*W_L + j]; - float diff = maxkoeLi[level*3+ dir-1] - koeLi[level*3 + dir-1][i*W_L + j]; - diff *= diffFactor; - koeLi[level*3 + dir-1][i*W_L + j] = maxkoeLi[level*3 + dir-1] - diff; - } - } - -} - - void ImProcFunctions::finalContAllL (int maxlvl, LabImage * labco, float ** varhue, float **varchrom, float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params &cp, - int W_L, int H_L, int skip, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveWL & waOpacityCurveWL, FlatCurve* ChCurve, bool Chutili) - { - bool lipschitz=true; - float edge=1.f; - bool curvdiag=true; - if(curvdiag && cp.finena) {//curve - float insigma=0.666f;//SD - float logmax=log(MaxP[level]);//log Max - float rapX=(mean[level]+sigma[level])/MaxP[level];//rapport between sD / max - float inx=log(insigma); - float iny=log(rapX); - float rap=inx/iny;//koef - float asig=0.166f/sigma[level]; - float bsig=0.5f-asig*mean[level]; - float amean=0.5f/mean[level]; - float absciss; - float kinterm; - float kmul; - for (int i=0; i= (mean[level]+sigma[level])){//for max - float valcour=log(fabs(WavCoeffs_L[dir][i])); - float valc=valcour-logmax; - float vald=valc*rap; - absciss=exp(vald); - - } - else if(fabs(WavCoeffs_L[dir][i])>=mean[level] && fabs(WavCoeffs_L[dir][i]) < (mean[level]+sigma[level])){ - absciss=asig*fabs(WavCoeffs_L[dir][i])+bsig; - } - // else if(fabs(WavCoeffs_L[dir][i]) < mean[level]){ - else - absciss=amean*fabs(WavCoeffs_L[dir][i]); - // } - kinterm=1.f; - kmul=1.f; - - float kc = kmul*(waOpacityCurveWL[absciss*500.f]-0.5f); - float reduceeffect=1.5f; - if(kc <=0.f) reduceeffect=1.f; - kinterm = 1.f + reduceeffect*kmul*(waOpacityCurveWL[absciss*500.f]-0.5f); - - if(kinterm<0.f) kinterm=0.01f; - } - - WavCoeffs_L[dir][i] *= kinterm; - } - } - int choicelevel = atoi(params->wavelet.Lmethod.data())-1; - choicelevel = choicelevel == -1 ? 4 : choicelevel; - - int choiceClevel=0; - if(params->wavelet.CLmethod=="one") choiceClevel=0; - else if(params->wavelet.CLmethod=="inf") choiceClevel=1; - else if(params->wavelet.CLmethod=="sup") choiceClevel=2; - else if(params->wavelet.CLmethod=="all") choiceClevel=3; - int choiceDir=0; - if(params->wavelet.Dirmethod=="one") choiceDir=1; - else if(params->wavelet.Dirmethod=="two") choiceDir=2; - else if(params->wavelet.Dirmethod=="thr") choiceDir=3; - else if(params->wavelet.Dirmethod=="all") choiceDir=0; - - int dir1 = (choiceDir == 2) ? 1 : 2; - int dir2 = (choiceDir == 3) ? 1 : 3; - if(choiceClevel<3) { // not all levels visible, paint residual - if(level == 0) { - if(cp.backm!=2) { // nothing to change when residual is used as background - float backGroundColor = (cp.backm==1) ? 12000.f : 0.f; - for (int i=0; i= cp.maxilev) { - for (int dir=1; dir<4; dir++) { - for (int i=0; i choicelevel) { - for (int dir=1; dir<4; dir++) { - for (int i=0; i= choicelevel - if(level > choicelevel) { - for (int i=0; i= choicelevel - if(choicelevel >= cp.maxilev) { - for (int dir=1; dir<4; dir++) { - for (int i=0; itop_right; - float t_l=settings->top_left; - float b_r=settings->bot_right; - float b_l=settings->bot_left; - float edd=settings->ed_detec; - float eddlow=settings->ed_low; - float eddstrength=settings->ed_detecStr; - float aedstr=(eddstrength-1.f)/90.f; - float bedstr=1.f-10.f*aedstr; - - bool refi=false; - // if(cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f) refi=true; - // if(cp.val > 0 || refi) {//edge - if(cp.val > 0 && cp.edgeena) { - float * koe; - float maxkoe=0.f; - if(lipschitz==false) { - koe = new float [H_L*W_L]; - for (int i=0; i=0.f && temp < thr) temp= thr; - if(temp < 0.f && temp > -thr) temp= -thr; - koe[i*W_L + j]= min(thr2,fabs(tmC[i][j]/temp)); - - if(koe[i*W_L + j] > maxkoe) maxkoe=koe[i*W_L + j]; - float diff=maxkoe-koe[i*W_L + j]; - diff *=(cp.eddet/100.f); - float interm=maxkoe-diff; - if(interm < cp.eddetthr/30.f) interm = 0.01f; - - koe[i*W_L + j]=interm; - - } - } - //printf("maxkoe=%f \n",maxkoe); - - for (int i=0; i not too high value to avoid artifacts - float value = ((float)cp.val)/8.f;//strength - if (scaleskip[1] < 1.f) value *= (atten01234*scaleskip[1]);//for zoom < 100% reduce strength...I choose level 1...but!! - float edge=1.f; - float lim0=20.f;//arbitrary limit for low radius and level between 2 or 3 to 30 maxi - float lev = float (level); - float repart=(float)cp.til; - float brepart; - if(cp.reinforce==1) brepart=3.f; - if(cp.reinforce==3) brepart=0.5f; //arbitrary value to increase / decrease repart, between 1 and 0 - float arepart=-(brepart-1.f)/(lim0/60.f); - if (cp.reinforce !=2) {if(rad < lim0/60.f) repart *= (arepart*rad + brepart);}//linear repartition of repart - - float al0 = 1.f + (repart)/50.f; - float al10 =1.0f;//arbitrary value ==> less = take into account high levels - // float ak =-(al0-al10)/10.f;//10 = maximum levels - float ak =-(al0-al10)/10.f;//10 = maximum levels - float bk =al0; - float koef = ak*level+bk;//modulate for levels : more levels high, more koef low ==> concentrated action on low levels, without or near for high levels - float expkoef= -pow(fabs(rad - lev),koef);//reduce effect for high levels - if (cp.reinforce==3) {if(rad < lim0/60.f && level==0) expkoef *= repart;}//reduce effect for low values of rad and level=0==> quasi only level 1 is effective - if (cp.reinforce==1) {if(rad < lim0/60.f && level==1) expkoef /= repart;}//increase effect for low values of rad and level=1==> quasi only level 0 is effective - float coefsd=0.85f;//arbitray value to reduce effect after sigma in all case - float coefmean=0.85f;//arbitray value to reduce effect after sigma in all case -// edge = 1.f + value * exp (expkoef);//estimate edge "pseudo variance" - //take into account local contrast - float refin= value * exp (expkoef); - if(cp.link==true && cp.noiseena){//combi - { - if(level==0) refin *= (1.f + cp.lev0s/50.f);// we can change this sensibility! - if(level==1) refin *= (1.f + cp.lev1s/50.f); - if(level==2) refin *= (1.f + cp.lev2s/50.f); - if(level==3) refin *= (1.f + cp.lev3s/50.f); - } - } - float edgePrecalc = 1.f + refin; //estimate edge "pseudo variance" - //bool exa=false; - if(cp.EDmet==2) {//curve - // if(exa) {//curve - float insigma=0.666f;//SD - float logmax=log(MaxP[level]);//log Max - float rapX=(mean[level]+sigma[level])/MaxP[level];//rapport between sD / max - float inx=log(insigma); - float iny=log(rapX); - float rap=inx/iny;//koef - float asig=0.166f/sigma[level]; - float bsig=0.5f-asig*mean[level]; - float amean=0.5f/mean[level]; - float absciss; - float kinterm; - float kmul; - // for (int i=0; i 10.f) edge=(aedstr*cp.eddet+bedstr)*(edgePrecalc*(1.f+koe[k]))/(1.f+0.9f*maxkoe); - else edge=(edgePrecalc*(1.f+koe[k]))/(1.f+0.9f*maxkoe); - } - if(lipschitz==true) { - if(level < 4) edge = 1.f +(edgePrecalc-1.f)*(koeLi[level*3][k])/(1.f+0.9f*maxkoeLi[level*3+ dir-1]); - else edge = edgePrecalc; - } - } - else edge = edgePrecalc; - - if(cp.edgcurv) { - if(fabs(WavCoeffs_L[dir][k])>= (mean[level]+sigma[level])){//for max - float valcour=log(fabs(WavCoeffs_L[dir][k])); - float valc=valcour-logmax; - float vald=valc*rap; - absciss=exp(vald); - - } - else if(fabs(WavCoeffs_L[dir][k])>=mean[level] && fabs(WavCoeffs_L[dir][k]) < (mean[level]+sigma[level])){ - absciss=asig*fabs(WavCoeffs_L[dir][k])+bsig; - } - else if(fabs(WavCoeffs_L[dir][k]) < mean[level]){ - absciss=amean*fabs(WavCoeffs_L[dir][k]); - } - // Threshold adjuster settings==> approximative for curve - //kmul about average cbrt(3--40 / 10)==>1.5 to 2.5 - //kmul about SD 10--60 / 35 ==> 2 - // kmul about low cbrt((5.f+cp.edg_low)/5.f);==> 1.5 - // kmul about max ==> 9 - // we can change these values - // result is different not best or bad than threshold slider...but similar - float abssd=4.f;//amplification reference - float bbssd=2.f;//mini ampli - float maxamp=2.5f;//maxi ampli at end - float maxampd=10.f;//maxi ampli at end - float a_abssd=(maxamp - abssd)/0.333f; - float b_abssd=maxamp-a_abssd; - float da_abssd=(maxampd - abssd)/0.333f; - float db_abssd=maxampd-da_abssd; - float am=(abssd-bbssd)/0.666f; - float kmuld=0.f; - if(absciss>0.666f && absciss < 1.f) {kmul=a_abssd*absciss + b_abssd;kmuld=da_abssd*absciss + db_abssd;}//about max ==> kinterm - else kmul = kmuld = absciss*am+bbssd; - kinterm=1.f; - float kc= kmul*(wavCLVCcurve[absciss*500.f]-0.5f); - float kcd= kmuld*(wavCLVCcurve[absciss*500.f]-0.5f); - float reduceeffect=0.6f; - if(kc >=0.f) - kinterm = 1.f + reduceeffect*kmul*(wavCLVCcurve[absciss*500.f]-0.5f);//about 1 to 3 general and big amplification for max (under 0) - else - kinterm = 1.f - (SQR(kcd))/10.f; - - if(kinterm<0.f) kinterm=0.01f; - edge *= kinterm; - if(edge < 1.f) - edge=1.f; - } - WavCoeffs_L[dir][k] *= edge; - } - } - } - else if(cp.EDmet==1) {//threshold adjuster - float MaxPCompare = MaxP[level]*SQR(cp.edg_max/100.f);//100 instead of b_r...case if b_r < 100 - float MaxNCompare = MaxN[level]*SQR(cp.edg_max/100.f);//always rduce a little edge for near max values - float edgeSdCompare = (mean[level]+1.5f*sigma[level])*SQR(cp.edg_sd/t_r);// 1.5 standard deviation #80% range between mean 50% and 80% - float edgeMeanCompare = mean[level]*SQR(cp.edg_mean/t_l); - float edgeLowCompare = (5.f+SQR(cp.edg_low)); - float edgeMeanFactor = cbrt(cp.edg_mean/t_l); - float interm; - if(cp.edg_low < 10.f) interm= cbrt((5.f+cp.edg_low)/5.f); - else interm=1.437f;//cbrt(3); - float edgeLowFactor = interm; - float edgeSdFactor = cp.edg_sd/t_r; - float edgeMaxFactor = SQR(cp.edg_max/b_r); - float edgMaxFsup=(cp.edg_max/b_r);//reduce increase of effect for high values contrast..if slider > b_r - - //for (int i=0; i 10.f) edge=(aedstr*cp.eddet+bedstr)*(edgePrecalc*(1.f+koe[k]))/(1.f+0.9f*maxkoe); - else edge=(edgePrecalc*(1.f+koe[k]))/(1.f+0.9f*maxkoe); - } - if(lipschitz==true) { - if(level < 4) edge = 1.f +(edgePrecalc-1.f)*(koeLi[level*3][k])/(1.f+0.9f*maxkoeLi[level*3+ dir-1]); - else edge = edgePrecalc; - } - } - else edge = edgePrecalc; - - //algorithm that take into account local contrast - // I use a thresholdadjuster with - // Bottom left ==> minimal low value for local contrast (not 0, but 5...we can change) - // 0 10*10 35*35 100*100 substantially correspond to the true distribution of low value, mean, standard-deviation and max (ed 5, 50, 400, 4000 - // Top left ==> mean reference value (for each level), we can change cbrt(cp.edg_mean/10.f) - // Top Right==> standard deviation (for each level) we can change (cp.edg_sd/35.f) - // bottom right ==> Max for positif and negatif contrast we can change cp.edg_max/100.f - // If we move sliders to the left, local contrast is reduced - // if we move sliders to the right local contrast is increased - // MaxP, MaxN, mean, sigma are calculated if necessary (val > 0) by evaluate2(), eval2(), aver() , sigma() - if(b_r < 100.f && cp.edg_max/b_r > 1.f) {//in case of b_r < 100 and slider move to right - if (WavCoeffs_L[dir][k] > MaxPCompare*cp.edg_max/b_r) { - edge *= edgMaxFsup; - if(edge < 1.f) - edge=1.f; - } - else if (WavCoeffs_L[dir][k] < MaxNCompare*cp.edg_max/b_r) { - edge *= edgMaxFsup; - if(edge < 1.f) - edge=1.f; - } - } - - if (WavCoeffs_L[dir][k] > MaxPCompare) { - edge *= edgeMaxFactor; - if(edge < 1.f) - edge=1.f; - }//reduce edge if > new max - else if (WavCoeffs_L[dir][k] < MaxNCompare) { - edge *= edgeMaxFactor; - if(edge < 1.f) - edge=1.f; - } - - if (fabs(WavCoeffs_L[dir][k]) >= edgeMeanCompare && fabs(WavCoeffs_L[dir][k]) < edgeSdCompare) { - //if (fabs(WavCoeffs_L[dir][i]) > edgeSdCompare) { - edge *= edgeSdFactor; - if(edge < 1.f) - edge=1.f; - }//mofify effect if sd change - if (fabs(WavCoeffs_L[dir][k]) < edgeMeanCompare) { - edge *= edgeMeanFactor; - if(edge < 1.f) - edge=1.f; - } // modify effect if mean change - if (fabs(WavCoeffs_L[dir][k]) < edgeLowCompare) { - edge *= edgeLowFactor; - if(edge < 1.f) - edge=1.f; - } - WavCoeffs_L[dir][k] *= edge; - } - } - } - if(lipschitz==false) { - delete [] koe; - } - } - - - if(cp.link==false && cp.noiseena) { //used both with denoise 1 2 3 - float refine=0.f; - for (int i=0; iwavelet.skinprotect; - const float skinprotneg = -skinprot; - const float factorHard = (1.f - skinprotneg/100.f); - - //to adjust increase contrast with local contrast - - //for each pixel and each level - float beta; - float mea[9]; - mea[0]=mean[level]/6.f; - mea[1]=mean[level]/2.f; - mea[2]=mean[level];// 50% data - mea[3]=mean[level] + sigma[level]/2.f; - mea[4]=mean[level] + sigma[level];//66% - mea[5]=mean[level] + 1.2f*sigma[level]; - mea[6]=mean[level] + 1.5f*sigma[level];// - mea[7]=mean[level] + 2.f*sigma[level];//95% - mea[8]=mean[level] + 2.5f*sigma[level];//99% - - bool skinControl = (skinprot != 0.f); - bool useChromAndHue = (skinprot != 0.f || cp.HSmet); - float modchro, kLlev; - - for (int i=0; iL[ii*2][jj*2]; - LL100=LL100init=LL/327.68f; - LL100res=WavCoeffs_L0[i]/327.68f; - float delta=fabs(LL100init-LL100res)/(maxlvl/2); - for(int ml=0;mlL[ii*2][jj*2]; - LL100=LL100init=LL/327.68f; - LL100res=WavCoeffs_L0[i]/327.68f; - float delta=fabs(LL100init-LL100res)/(maxlvl/2); - for(int ml=0;ml 0.f){ - Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); //0 for skin and extand - } else if(skinprot < 0.f){ - Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); - if (scale == 1.f) - scale=factorHard; - else - scale=1.f; - } - - } - if(Chutili){ - int i_i=i/W_L; - int j_j=i-i_i*W_L; - double lr; - float modhue2 = varhue[i_i][j_j]; - float valparam = float((ChCurve->getVal(lr=Color::huelab_to_huehsv2(modhue2))-0.5f));//get valparam=f(H) - - if(valparam > 0.f) scale2=1.f + 3.f* valparam;//arbitrary value - else scale2 = 1.f + 1.9f*valparam;//near 0 but not zero if curve # 0 - - //curve Contrast / hue - - } - // - //linear transition HL - float diagacc=1.f; - /* - if(cp.diag) { - if(dir <=2) diagacc=0.75f; - if(dir ==3) diagacc=1.5f; - } - */ - float alpha = (1024.f + 15.f *(float) cpMul*scale*scale2*beta*diagacc)/1024.f ; - if(cp.HSmet && cp.chromena){ - float aaal=(1.f-alpha)/((cp.b_lhl-cp.t_lhl)*kH[level]); - float bbal=1.f-aaal*cp.b_lhl*kH[level]; - float aaar=(alpha-1.f)/(cp.t_rhl-cp.b_rhl)*kH[level]; - float bbbr=1.f-cp.b_rhl*aaar*kH[level]; - //linear transition Shadows - float aaalS=(1.f-alpha)/(cp.b_lsl-cp.t_lsl); - float bbalS=1.f-aaalS*cp.b_lsl; - float aaarS=(alpha-1.f)/(cp.t_rsl-cp.b_rsl); - float bbbrS=1.f-cp.b_rsl*aaarS; - if(level <=cp.numlevH) {//in function of levels - if((LL100 > cp.t_lhl*kH[level] && LL100 < cp.t_rhl*kH[level])) {kLlev=alpha;} - else if((LL100 > cp.b_lhl*kH[level] && LL100 <= cp.t_lhl*kH[level])) kLlev=aaal*LL100+bbal; - else if((LL100 > cp.t_rhl*kH[level] && LL100 <= cp.b_rhl*kH[level])) kLlev=aaar*LL100+bbbr; - else kLlev=1.f; - } - if(level >=(9-cp.numlevS)) { - if((LL100 > cp.t_lsl && LL100 < cp.t_rsl)) kLlev=alpha; - else if((LL100 > cp.b_lsl && LL100 <= cp.t_lsl)) kLlev=aaalS*LL100+bbalS; - else if((LL100 > cp.t_rsl && LL100 <= cp.b_rsl)) kLlev=aaarS*LL100+bbbrS; - else kLlev=1.f; - } - - } - else kLlev=alpha; - - WavCoeffs_L[dir][i]*=(kLlev); - } - } -if(waOpacityCurveW) cp.opaW=true; - -if(cp.bam && cp.finena) { -if(cp.opaW && cp.BAmet==2){ - int iteration = cp.ite; - int itplus=7+iteration; - int itmoins= 7-iteration; - int med = maxlvl/2; - int it; - if(level < med) {it=itmoins; } - else if(level == med) it=7; - else if(level > med) it=itplus; - - for(int j=0; j < it; j++) { - //float bal = cp.balan;//-100 +100 - float kba=1.f; - float k1; - float k2; - // if(dir <3) kba= 1.f + bal/600.f; - // if(dir==3) kba = 1.f - bal/300.f; - for (int i=0; iL[ii*2][jj*2]/327.68f; - k1=600.f; - k2=300.f; - k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16 - k2=k1*2.f; - if(dir <3) kba= 1.f + k1; - if(dir==3) kba = 1.f - k2; - - WavCoeffs_L[dir][i] *=(kba); - } - } -} -if(cp.BAmet==1){ - int iteration = cp.ite; - int itplus=7+iteration; - int itmoins= 7-iteration; - int med = maxlvl/2; - int it; - if(level < med) {it=itmoins; } - else if(level == med) it=7; - else if(level > med) it=itplus; - - for(int j=0; j < it; j++) { - float bal = cp.balan;//-100 +100 - float kba=1.f; - float k1; - float k2; - // if(dir <3) kba= 1.f + bal/600.f; - // if(dir==3) kba = 1.f - bal/300.f; - for (int i=0; iL[ii*2][jj*2]/327.68f; - float aa=4970.f; - float bb=-397000.f; - float b0=100000.f; - float a0=-4970.f; - if(LL100> 80.f) {k1=aa*LL100 + bb;k2=0.5f*k1;} - if(LL100< 20.f) {k1=a0*LL100 + b0;k2=0.5f*k1;} - //k1=600.f; - //k2=300.f; - //k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16 - //k2=k1*2.f; - if(dir <3) kba= 1.f + bal/k1; - if(dir==3) kba = 1.f - bal/k2; - - WavCoeffs_L[dir][i] *=(kba); - } - } -} - -} - - // to see each level of wavelet ...level from 0 to 8 - int choicelevel = atoi(params->wavelet.Lmethod.data())-1; - choicelevel = choicelevel == -1 ? 4 : choicelevel; - } - - void ImProcFunctions::ContAllAB (LabImage * labco, int maxlvl, float ** varhue, float **varchrom, float ** WavCoeffs_ab, float * WavCoeffs_ab0, int level, int dir, const WavOpacityCurveW & waOpacityCurveW, struct cont_params &cp, - int W_ab, int H_ab, const bool useChannelA) - { - float cpMul = cp.mul[level]; - if(cpMul != 0.f && cp.CHmet==2 && cp.chro != 0.f && cp.chromena) { // cpMul == 0.f or cp.chro = 0.f means all will be multiplied by 1.f, so we can skip this - const float skinprot = params->wavelet.skinprotect; - const float skinprotneg = -skinprot; - const float factorHard = (1.f - skinprotneg/100.f); - const float cpChrom = cp.chro; - - //to adjust increase contrast with local contrast - bool useSkinControl = (skinprot != 0.f); - float alphaC =(1024.f + 15.f *cpMul*cpChrom/50.f)/1024.f ; - for (int i=0; iL[ii*2][jj*2]/327.68f; - float modhue = varhue[ii][jj]; - float modchro = varchrom[ii*2][jj*2]; - // hue chroma skin with initial lab datas - float scale=1.f; - if(skinprot > 0.f){ - Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); //0 for skin and extand - } else if(skinprot < 0.f){ - Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); - scale = (scale == 1.f) ? factorHard : 1.f; - } - alphaC =(1024.f + 15.f *cpMul*cpChrom*scale/50.f)/1024.f ; - } - WavCoeffs_ab[dir][i] *= alphaC; - } - } - //Curve chro - - float cpMulC = cp.mulC[level]; - // if( (cp.curv || cp.CHSLmet==1) && cp.CHmet!=2 && level < 9 && cpMulC != 0.f) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip - if( cp.CHmet!=2 && level < 9 && cpMulC != 0.f && cp.chromena) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip - float modchro, modhue, kClev; - const float skinprot = params->wavelet.skinprotect; - const float skinprotneg = -skinprot; - const float factorHard = (1.f - skinprotneg/100.f); - bool useSkinControl = (skinprot != 0.f); - - for (int i=0; iL[ii*2][jj*2]; - float LL100=LL/327.68f; - float scale=1.f; - modchro = varchrom[ii*2][jj*2]; - - if(useSkinControl) { - // hue chroma skin with initial lab datas - modhue = varhue[ii][jj]; - scale=1.f; - if(skinprot > 0.f){ - Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 1); //1 for curve - } - else if(skinprot < 0.f){ - Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 1); - scale = (scale == 1.f) ? factorHard : 1.f; - } - } - float beta = (1024.f + 20.f * cpMulC * scale)/1024.f ; - if(beta < 0.02f) - beta=0.02f; - kClev = beta; - if(cp.CHmet==1){ - if(level < cp.chrom) { - //linear for saturated - if((modchro > cp.t_lsat && modchro < cp.t_rsat)) - kClev=beta; - else if((modchro > cp.b_lsat && modchro <= cp.t_lsat)) { - float aaal=(1.f-beta)/(cp.b_lsat-cp.t_lsat); - float bbal=1.f-aaal*cp.b_lsat; - kClev=aaal*modchro+bbal; - } else if((modchro > cp.t_rsat && modchro <= cp.b_rsat)) { - float aaar=(beta-1.f)/(cp.t_rsat-cp.b_rsat); - float bbbr=1.f-cp.b_rsat*aaar; - kClev=aaar*modchro+bbbr; - } else - kClev=1.f; - } else { - //linear for pastel - if((modchro > cp.t_lpast && modchro < cp.t_rpast)) - kClev=beta; - else if((modchro > cp.b_lpast && modchro <= cp.t_lpast)) { - float aaalS=(1.f-beta)/(cp.b_lpast-cp.t_lpast); - float bbalS=1.f-aaalS*cp.b_lpast; - kClev=aaalS*modchro+bbalS; - } else if((modchro > cp.t_rpast && modchro <= cp.b_rpast)) { - float aaarS=(beta-1.f)/(cp.t_rpast-cp.b_rpast); - float bbbrS=1.f-cp.b_rpast*aaarS; - kClev=aaarS*modchro+bbbrS; - } else - kClev=1.f; - } - } - else if(cp.CHmet==0) - kClev=beta; - WavCoeffs_ab[dir][i] *= kClev; - } - } - - bool useOpacity; - float mulOpacity; - if(useChannelA) { - useOpacity = cp.opaRG; - mulOpacity = cp.mulopaRG[level]; - } - else { - useOpacity = cp.opaBY; - mulOpacity = cp.mulopaBY[level]; - } - - if((useOpacity && level < 9 && mulOpacity != 0.f) && cp.toningena) { //toning - - float beta = (1024.f + 20.f * mulOpacity)/1024.f ; - //float beta = (1000.f * mulOpacity); - for (int i=0; i med) it=itplus; - - for(int j=0; j < it; j++) { - //float bal = cp.balan;//-100 +100 - float kba=1.f; - float k1; - float k2; - // if(dir <3) kba= 1.f + bal/600.f; - // if(dir==3) kba = 1.f - bal/300.f; - for (int i=0; iL[ii*2][jj*2]/327.68f; - k1=600.f; - k2=300.f; - k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16 - k2=k1*2.f; - if(dir <3) kba= 1.f + k1; - if(dir==3) kba = 1.f - k2; - - WavCoeffs_ab[dir][i] *=(kba); - } - } -} -if(cp.BAmet==1){ - int iteration = cp.ite; - int itplus=7+iteration; - int itmoins= 7-iteration; - int med = maxlvl/2; - int it; - if(level < med) {it=itmoins; } - else if(level == med) it=7; - else if(level > med) it=itplus; - - for(int j=0; j < it; j++) { - float bal = cp.balan;//-100 +100 - float kba=1.f; - float k1; - float k2; - // if(dir <3) kba= 1.f + bal/600.f; - // if(dir==3) kba = 1.f - bal/300.f; - for (int i=0; iL[ii*2][jj*2]/327.68f; - float aa=4970.f; - float bb=-397000.f; - float b0=100000.f; - float a0=-4970.f; - if(LL100> 80.f) {k1=aa*LL100 + bb;k2=0.5f*k1;} - if(LL100< 20.f) {k1=a0*LL100 + b0;k2=0.5f*k1;} - //k1=600.f; - //k2=300.f; - //k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16 - //k2=k1*2.f; - if(dir <3) kba= 1.f + bal/k1; - if(dir==3) kba = 1.f - bal/k2; - - WavCoeffs_ab[dir][i] *=(kba); - } - } -} - -} - - // to see each level of wavelet ...level from 0 to 8 - int choicelevel = atoi(params->wavelet.Lmethod.data())-1; - choicelevel = choicelevel == -1 ? 4 : choicelevel; - int choiceClevel=0; - if(params->wavelet.CLmethod=="one") choiceClevel=0; - else if(params->wavelet.CLmethod=="inf") choiceClevel=1; - else if(params->wavelet.CLmethod=="sup") choiceClevel=2; - else if(params->wavelet.CLmethod=="all") choiceClevel=3; - int choiceDir=0; - if(params->wavelet.Dirmethod=="one") choiceDir=1; - else if(params->wavelet.Dirmethod=="two") choiceDir=2; - else if(params->wavelet.Dirmethod=="thr") choiceDir=3; - else if(params->wavelet.Dirmethod=="all") choiceDir=0; - - int dir1 = (choiceDir == 2) ? 1 : 2; - int dir2 = (choiceDir == 3) ? 1 : 3; - if(choiceClevel<3) { // not all levels visible, paint residual - if(level == 0) { - if(cp.backm!=2) { // nothing to change when residual is used as background - float backGroundChroma = (cp.backm==1) ? 0.f : 0.f;//we can change first to colorized... - for (int i=0; i= cp.maxilev) { - for (int dir=1; dir<4; dir++) { - for (int i=0; i choicelevel) { - for (int dir=1; dir<4; dir++) { - for (int i=0; i= choicelevel - if(level > choicelevel) { - for (int i=0; i= choicelevel - if(choicelevel >= cp.maxilev) { - for (int dir=1; dir<4; dir++) { - for (int i=0; i. +// * 2014 Jacques Desmis +// * 2014 Ingo Weyrich + +// +//////////////////////////////////////////////////////////////// + + + +#include +#include "../rtgui/threadutils.h" + +#include "rtengine.h" +#include "improcfun.h" +#include "LUT.h" +#include "array2D.h" +#include "boxblur.h" +#include "rt_math.h" +#include "mytime.h" +#include "sleef.c" +#include "opthelper.h" +#include "StopWatch.h" +#include "EdgePreservingDecomposition.h" + +#ifdef _OPENMP +#include +#endif + +#include "cplx_wavelet_dec.h" + +#define TS 64 // Tile size +#define offset 25 // shift between tiles +#define fTS ((TS/2+1)) // second dimension of Fourier tiles +#define blkrad 1 // radius of block averaging + +#define PIX_SORT(a,b) { if ((a)>(b)) {temp=(a);(a)=(b);(b)=temp;} } + +#define med3(a0,a1,a2,a3,a4,a5,a6,a7,a8,median) { \ +pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; pp[5]=a5; pp[6]=a6; pp[7]=a7; pp[8]=a8; \ +PIX_SORT(pp[1],pp[2]); PIX_SORT(pp[4],pp[5]); PIX_SORT(pp[7],pp[8]); \ +PIX_SORT(pp[0],pp[1]); PIX_SORT(pp[3],pp[4]); PIX_SORT(pp[6],pp[7]); \ +PIX_SORT(pp[1],pp[2]); PIX_SORT(pp[4],pp[5]); PIX_SORT(pp[7],pp[8]); \ +PIX_SORT(pp[0],pp[3]); PIX_SORT(pp[5],pp[8]); PIX_SORT(pp[4],pp[7]); \ +PIX_SORT(pp[3],pp[6]); PIX_SORT(pp[1],pp[4]); PIX_SORT(pp[2],pp[5]); \ +PIX_SORT(pp[4],pp[7]); PIX_SORT(pp[4],pp[2]); PIX_SORT(pp[6],pp[4]); \ +PIX_SORT(pp[4],pp[2]); median=pp[4];} //pp4 = median + + +#define med2(a0,a1,a2,a3,a4,median) { \ +pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; \ +PIX_SORT(pp[0],pp[1]) ; PIX_SORT(pp[3],pp[4]) ; PIX_SORT(pp[0],pp[3]) ;\ +PIX_SORT(pp[1],pp[4]) ; PIX_SORT(pp[1],pp[2]) ; PIX_SORT(pp[2],pp[3]) ;\ +PIX_SORT(pp[1],pp[2]) ; median=pp[2] ;} + + +#define epsilon 0.001f/(TS*TS) //tolerance + + +namespace rtengine { + +extern const Settings* settings; + +struct cont_params { + float mul[10]; + int chrom; + int chro; + int contrast; + float th; + float thH; + float conres; + float conresH; + float chrores; + float hueres; + float sky; + float b_l,t_l,b_r,t_r; + float b_ly,t_ly,b_ry,t_ry; + float b_lsl,t_lsl,b_rsl,t_rsl; + float b_lhl,t_lhl,b_rhl,t_rhl; + float edg_low, edg_mean, edg_sd, edg_max; + float lev0s, lev0n, lev1s, lev1n, lev2s, lev2n, lev3s, lev3n; + float b_lpast,t_lpast,b_rpast,t_rpast; + float b_lsat,t_lsat,b_rsat,t_rsat; + int rad; + int val; + int til; + int numlevH, numlevS; + float mulC[9]; + float mulopaRG[9]; + float mulopaBY[9]; + bool curv; + bool opaBY; + bool opaRG; + bool edgcurv; + bool diagcurv; + int CHmet; + int CHSLmet; + int EDmet; + bool HSmet; + bool avoi; + float strength; + int reinforce; + bool detectedge; + int backm; + float eddet; + float eddetthr; + bool lips; + float eddetthrHi; + bool link; + bool lip3; + bool tonemap; + bool diag; + int TMmeth; + float tmstrength; + float balan; + int ite; + int contmet; + bool opaW; + int BAmet; + bool bam; + float blhigh; + float grhigh; + float blmed; + float grmed; + float bllow; + float grlow; + bool cbena; + bool contena; + bool chromena; + bool edgeena; + bool resena; + bool finena; + bool toningena; + bool noiseena; + int maxilev; + float edgsens; + float edgampl; + int neigh; + bool lipp; +}; + +int wavNestedLevels = 1; + + +SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const procparams::WaveletParams & waparams, const WavCurve & wavCLVCcurve, const WavOpacityCurveRG & waOpacityCurveRG, const WavOpacityCurveBY & waOpacityCurveBY, const WavOpacityCurveW & waOpacityCurveW, const WavOpacityCurveWL & waOpacityCurveWL, LUTf &wavclCurve, bool wavcontlutili, int skip) + + +{ + MyTime t1e,t2e ; + t1e.set(); + +#ifdef _DEBUG + // init variables to display Munsell corrections + MunsellDebugInfo* MunsDebugInfo = new MunsellDebugInfo(); +#endif + TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); + double wip[3][3] = { + {wiprof[0][0],wiprof[0][1],wiprof[0][2]}, + {wiprof[1][0],wiprof[1][1],wiprof[1][2]}, + {wiprof[2][0],wiprof[2][1],wiprof[2][2]} + }; + const short int imheight=lab->H, imwidth=lab->W; + struct cont_params cp; + cp.avoi = params->wavelet.avoid; + if(params->wavelet.Medgreinf=="more") cp.reinforce = 1; + if(params->wavelet.Medgreinf=="none") cp.reinforce = 2; + if(params->wavelet.Medgreinf=="less") cp.reinforce = 3; + + if(params->wavelet.NPmethod=="none") cp.lip3 = false; + if(params->wavelet.NPmethod=="low") {cp.lip3 = true;cp.neigh=0;} + if(params->wavelet.NPmethod=="high") {cp.lip3 = true;cp.neigh=1;} + + cp.lipp = params->wavelet.lipst; + cp.diag = params->wavelet.tmr; + cp.balan = (float)params->wavelet.balance; + cp.ite = params->wavelet.iter; + cp.tonemap=false; + cp.bam=false; + if(params->wavelet.tmrs==0) cp.tonemap=false; + else cp.tonemap=true; + /*else if(params->wavelet.TMmethod=="std") {cp.TMmeth=1;cp.tonemap=true;} + else if(params->wavelet.TMmethod=="high") {cp.TMmeth=2;cp.tonemap=true;} + else if(params->wavelet.TMmethod=="lowhigh") {cp.TMmeth=3;cp.tonemap=true;} + */ + if(params->wavelet.TMmethod=="cont") cp.contmet=1; + else if(params->wavelet.TMmethod=="tm") cp.contmet=2; + + if(params->wavelet.BAmethod!="none") cp.bam=true; + if(params->wavelet.BAmethod=="sli") cp.BAmet=1; + if(params->wavelet.BAmethod=="cur") cp.BAmet=2; + + cp.tmstrength=params->wavelet.tmrs; + //cp.tonemap = params->wavelet.tmr; + cp.contena=true; + cp.contena=params->wavelet.expcontrast; + cp.chromena=true; + cp.chromena=params->wavelet.expchroma; + cp.edgeena=true; + cp.edgeena=params->wavelet.expedge; + cp.resena=true; + cp.resena=params->wavelet.expresid; + cp.finena=true; + cp.finena=params->wavelet.expfinal; + cp.toningena=true; + cp.toningena=params->wavelet.exptoning; + cp.noiseena=true; + cp.noiseena=params->wavelet.expnoise; + + if(params->wavelet.Backmethod=="black") cp.backm= 0; + if(params->wavelet.Backmethod=="grey") cp.backm = 1; + if(params->wavelet.Backmethod=="resid") cp.backm = 2; + cp.link=params->wavelet.linkedg; + cp.eddet=(float) params->wavelet.edgedetect; + cp.eddetthr=(float) params->wavelet.edgedetectthr; + cp.eddetthrHi=(float) params->wavelet.edgedetectthr2; + + cp.edgsens=60.f; + cp.edgampl=10.f; + if(cp.lipp) { + cp.edgsens=(float) params->wavelet.edgesensi; + cp.edgampl=(float) params->wavelet.edgeampli; + } + int N=imheight*imwidth; + int maxmul=params->wavelet.thres; + cp.maxilev=maxmul; + static const float scales[10] = {1.f,2.f,4.f,8.f,16.f,32.f,64.f,128.f,256.f,512.f}; + float scaleskip[10]; + for(int sc=0;sc<10;sc++) + scaleskip[sc]=scales[sc]/skip; + float atten0 = 0.40f; + float atten123=0.90f; + + //int DaubLen = settings->daubech ? 8 : 6; + int DaubLen; + if(params->wavelet.daubcoeffmethod=="2_") DaubLen=4; + if(params->wavelet.daubcoeffmethod=="4_") DaubLen=6; + if(params->wavelet.daubcoeffmethod=="6_") DaubLen=8; + if(params->wavelet.daubcoeffmethod=="10_") DaubLen=12; + if(params->wavelet.daubcoeffmethod=="14_") DaubLen=16; + + cp.CHSLmet=1; +// if(params->wavelet.CHSLmethod=="SL") cp.CHSLmet=1; +// if(params->wavelet.CHSLmethod=="CU") cp.CHSLmet=2; + cp.EDmet=1; + if(params->wavelet.EDmethod=="SL") cp.EDmet=1; + if(params->wavelet.EDmethod=="CU") cp.EDmet=2; + + cp.cbena= params->wavelet.cbenab; + cp.blhigh=(float)params->wavelet.bluehigh; + cp.grhigh=(float)params->wavelet.greenhigh; + cp.blmed=(float)params->wavelet.bluemed; + cp.grmed=(float)params->wavelet.greenmed; + cp.bllow=(float)params->wavelet.bluelow; + cp.grlow=(float)params->wavelet.greenlow; + cp.curv=false; + cp.edgcurv=false; + cp.diagcurv=false; + cp.opaRG=false; + cp.opaBY=false; + cp.opaW=false; + cp.CHmet=0; + cp.HSmet=false; + if(params->wavelet.CHmethod=="with") cp.CHmet=1; + if(params->wavelet.CHmethod=="link") cp.CHmet=2; + if(params->wavelet.HSmethod=="with") cp.HSmet=true; + + cp.strength = min(1.f,max(0.f,((float)params->wavelet.strength / 100.f))); + + for(int m=0;mverbose) printf("Wav mul 0=%f 1=%f 2=%f 3=%f 4=%f 5=%f 6=%f 7=%f 8=%f 9=%f\n",cp.mul[0],cp.mul[1],cp.mul[2],cp.mul[3],cp.mul[4],cp.mul[5],cp.mul[6],cp.mul[7],cp.mul[8],cp.mul[9]); + for(int sc=0;sc<9;sc++) {//reduce strength if zoom < 100% for chroma and tuning + if(sc==0) {if(scaleskip[sc] < 1.f) {cp.mulC[sc]*=(atten0*scaleskip[sc]);cp.mulopaRG[sc]*=(atten0*scaleskip[sc]);cp.mulopaBY[sc]*=(atten0*scaleskip[sc]);}} + else {if(scaleskip[sc] < 1.f) {cp.mulC[sc]*=(atten123*scaleskip[sc]);cp.mulopaRG[sc]*=(atten123*scaleskip[sc]);cp.mulopaBY[sc]*=(atten123*scaleskip[sc]);}} + } + + cp.chro=waparams.chro; + cp.chrom=waparams.chroma; + cp.contrast=waparams.contrast; + cp.rad=waparams.edgrad; + cp.val=waparams.edgval; + cp.til=waparams.edgthresh; + + cp.conres=waparams.rescon; + cp.conresH=waparams.resconH; + cp.chrores=waparams.reschro; + //cp.hueres=waparams.reshue; + cp.hueres=2.f; + cp.th=float(waparams.thr); + cp.thH=float(waparams.thrH); + cp.sky=waparams.sky; + //skin + cp.b_l = static_cast(params->wavelet.hueskin.value[0]) / 100.0f; + cp.t_l = static_cast(params->wavelet.hueskin.value[1]) / 100.0f; + cp.b_r = static_cast(params->wavelet.hueskin.value[2]) / 100.0f; + cp.t_r = static_cast(params->wavelet.hueskin.value[3]) / 100.0f; + + cp.b_ly = static_cast(params->wavelet.hueskin2.value[0]) / 100.0f; + cp.t_ly = static_cast(params->wavelet.hueskin2.value[1]) / 100.0f; + cp.b_ry = static_cast(params->wavelet.hueskin2.value[2]) / 100.0f; + cp.t_ry = static_cast(params->wavelet.hueskin2.value[3]) / 100.0f; + cp.numlevH=params->wavelet.threshold; + + //shadows + cp.b_lsl = static_cast(params->wavelet.bllev.value[0]); + cp.t_lsl = static_cast(params->wavelet.bllev.value[1]); + cp.b_rsl = static_cast(params->wavelet.bllev.value[2]); + cp.t_rsl = static_cast(params->wavelet.bllev.value[3]); + cp.numlevS=params->wavelet.threshold2; + int maxlevS=9-cp.numlevH; + cp.numlevS = MIN(cp.numlevS,maxlevS); + //printf("levHigh=%d levShad=%d\n",cp.numlevH,cp.numlevS); + //highlight + cp.b_lhl = static_cast(params->wavelet.hllev.value[0]); + cp.t_lhl = static_cast(params->wavelet.hllev.value[1]); + cp.b_rhl = static_cast(params->wavelet.hllev.value[2]); + cp.t_rhl = static_cast(params->wavelet.hllev.value[3]); + //printf("BL=%f TL=%f BR=%f TR=%f\n",cp.b_lhl,cp.t_lhl,cp.b_rhl,cp.t_rhl); + //pastel + cp.b_lpast = static_cast(params->wavelet.pastlev.value[0]); + cp.t_lpast = static_cast(params->wavelet.pastlev.value[1]); + cp.b_rpast = static_cast(params->wavelet.pastlev.value[2]); + cp.t_rpast = static_cast(params->wavelet.pastlev.value[3]); + //saturated + cp.b_lsat = static_cast(params->wavelet.satlev.value[0]); + cp.t_lsat = static_cast(params->wavelet.satlev.value[1]); + cp.b_rsat = static_cast(params->wavelet.satlev.value[2]); + cp.t_rsat = static_cast(params->wavelet.satlev.value[3]); + //edge local contrast + cp.edg_low = static_cast(params->wavelet.edgcont.value[0]); + cp.edg_mean = static_cast(params->wavelet.edgcont.value[1]); + cp.edg_max = static_cast(params->wavelet.edgcont.value[2]); + cp.edg_sd = static_cast(params->wavelet.edgcont.value[3]); + //level noise + cp.lev0s =static_cast(params->wavelet.level0noise.value[0]); + cp.lev0n =static_cast(params->wavelet.level0noise.value[1]); + cp.lev1s =static_cast(params->wavelet.level1noise.value[0]); + cp.lev1n =static_cast(params->wavelet.level1noise.value[1]); + cp.lev2s =static_cast(params->wavelet.level2noise.value[0]); + cp.lev2n =static_cast(params->wavelet.level2noise.value[1]); + cp.lev3s =static_cast(params->wavelet.level3noise.value[0]); + cp.lev3n =static_cast(params->wavelet.level3noise.value[1]); + + cp.detectedge = false; + cp.detectedge = params->wavelet.medianlev; + //printf("low=%f mean=%f sd=%f max=%f\n",cp.edg_low,cp.edg_mean,cp.edg_sd,cp.edg_max); + int minwin=min(imwidth,imheight); + int maxlevelcrop=9; + if(cp.mul[9]!=0) + maxlevelcrop=10; + // adap maximum level wavelet to size of crop + if(minwin*skip < 1024) maxlevelcrop = 9;//sampling wavelet 512 + if(minwin*skip < 512) maxlevelcrop = 8;//sampling wavelet 256 + if(minwin*skip < 256) maxlevelcrop = 7;//sampling 128 + if(minwin*skip < 128) maxlevelcrop = 6; + if(minwin < 64) maxlevelcrop = 5; + // printf("minwin=%d maxcrop=%d\n",minwin, maxlevelcrop); + + int levwav=params->wavelet.thres; + if(levwav==9 && cp.mul[9]!=0) levwav=10; + levwav=min(maxlevelcrop,levwav); + // determine number of levels to process. + // for(levwav=min(maxlevelcrop,levwav);levwav>0;levwav--) + // if(cp.mul[levwav-1]!=0.f || cp.curv) + // if(cp.mul[levwav-1]!=0.f) + // break; + // I suppress this fonctionality ==> crash for level < 3 + if(levwav<1) + return; // nothing to do + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // begin tile processing of image + + //output buffer + int realtile; + if(params->wavelet.Tilesmethod=="big") realtile=22; + if(params->wavelet.Tilesmethod=="lit") realtile=12; + + int tilesize; + int overlap; + tilesize = 1024; + overlap = 128; + //tilesize=128*params->wavelet.tiles; + tilesize=128*realtile; + //overlap=(int) tilesize*params->wavelet.overl; + overlap=(int) tilesize*0.125f; + // printf("overl=%d\n",overlap); + int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; + if(params->wavelet.Tilesmethod=="full") kall=0; + Tile_calc (tilesize, overlap, kall, imwidth, imheight, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip); + + const int numtiles = numtiles_W*numtiles_H; + LabImage * dsttmp; + if(numtiles == 1) { + dsttmp = dst; + } else { + dsttmp = new LabImage(imwidth,imheight); + for (int n=0; n<3*imwidth*imheight; n++) dsttmp->data[n] = 0; + } + //now we have tile dimensions, overlaps + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + int minsizetile=min(tilewidth, tileheight); + int maxlev2=10; + if(minsizetile < 1024 && levwav==10) maxlev2 = 9; + if(minsizetile < 512) maxlev2 = 8; + if(minsizetile < 256) maxlev2 = 7; + if(minsizetile < 128) maxlev2 = 6; + levwav=min(maxlev2,levwav); + + //printf("levwav = %d\n",levwav); + + int numthreads = 1; + int maxnumberofthreadsforwavelet =0; + //reduce memory for big tile size + if(kall!=0) { + if(realtile <= 22) maxnumberofthreadsforwavelet=2; + if(realtile <= 20) maxnumberofthreadsforwavelet=3; + if(realtile <= 18) maxnumberofthreadsforwavelet=4; + if(realtile <= 16) maxnumberofthreadsforwavelet=6; + if(realtile <= 14) maxnumberofthreadsforwavelet=8; + //printf("maxNRT=%d\n",maxnumberofthreadsforwavelet); + if((maxnumberofthreadsforwavelet==6 || maxnumberofthreadsforwavelet==8) && levwav==10) maxnumberofthreadsforwavelet-=2; + if(levwav <=7 && maxnumberofthreadsforwavelet ==8) maxnumberofthreadsforwavelet=0; + } + //printf("maxthre=%d\n",maxnumberofthreadsforwavelet); + +#ifdef _OPENMP + // Calculate number of tiles. If less than omp_get_max_threads(), then limit num_threads to number of tiles + if( options.rgbDenoiseThreadLimit>0) + maxnumberofthreadsforwavelet = min(max(options.rgbDenoiseThreadLimit / 2, 1), maxnumberofthreadsforwavelet); + + numthreads = MIN(numtiles,omp_get_max_threads()); + if(maxnumberofthreadsforwavelet > 0) + numthreads = MIN(numthreads,maxnumberofthreadsforwavelet); +#ifdef _RT_NESTED_OPENMP + wavNestedLevels = omp_get_max_threads() / numthreads; + bool oldNested = omp_get_nested(); + if(wavNestedLevels < 2) + wavNestedLevels = 1; + else + omp_set_nested(true); + if(maxnumberofthreadsforwavelet > 0) + while(wavNestedLevels*numthreads > maxnumberofthreadsforwavelet) + wavNestedLevels--; +#endif + if(settings->verbose) + printf("Ip Wavelet uses %d main thread(s) and up to %d nested thread(s) for each main thread\n",numthreads,wavNestedLevels); + + +#endif + +#ifdef _OPENMP +#pragma omp parallel num_threads(numthreads) +#endif +{ + float *mean = new float [9]; + float *meanN = new float [9]; + float *sigma = new float [9]; + float *sigmaN = new float [9]; + float *MaxP = new float [9]; + float *MaxN = new float [9]; + + float** varhue = new float*[tileheight]; + for (int i=0; i we can use output buffer for labco + labco = dst; + if(cp.avoi) { // we need a buffer to hold a copy of the L channel + Lold = new float*[tileheight]; + LoldBuffer = new float[tilewidth*tileheight]; + memcpy(LoldBuffer, lab->L[0], tilewidth*tileheight*sizeof(float)); + for (int i=0; iL; + } + +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(wavNestedLevels) if(wavNestedLevels>1) +#endif + + for (int i=tiletop; ia[i][j]); + bv = LVFU(lab->b[i][j]); + huev = xatan2f(bv,av); + chrov = _mm_sqrt_ps(SQRV(av)+SQRV(bv)) / c327d68v; + _mm_storeu_ps(&varhue[i1][j1],huev); + _mm_storeu_ps(&varchro[i1][j1], chrov); + if(labco != lab) { + _mm_storeu_ps(&(labco->L[i1][j1]),LVFU(lab->L[i][j])); + _mm_storeu_ps(&(labco->a[i1][j1]),av); + _mm_storeu_ps(&(labco->b[i1][j1]),bv); + } + } +#else + j=tileleft; +#endif + for (; ja[i][j]; + float b=lab->b[i][j]; + varhue[i1][j1]=xatan2f(b,a); + varchro[i1][j1]=(sqrtf(a*a+b*b))/327.68f; + if(labco != lab) { + labco->L[i1][j1] = lab->L[i][j]; + labco->a[i1][j1] = a; + labco->b[i1][j1] = b; + } + } + } + //to avoid artifacts in blue sky + if(params->wavelet.median) { + float** tmL; + int wid=labco->W; + int hei=labco->H; + int borderL = 1; + tmL = new float*[hei]; + for (int i=0; iL[i][j]; + } + } + +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for num_threads(wavNestedLevels) if(wavNestedLevels>1) +#endif + for (int i=1; i - 2.5f) && (varchro[i][j] > 15.f && varchro[i][j] < 55.f) && labco->L[i][j] > 6000.f) //blue sky + med3x3 ==> after for more effect use denoise + med3(labco->L[i][j] ,labco->L[i-1][j], labco->L[i+1][j] ,labco->L[i][j+1],labco->L[i][j-1], labco->L[i-1][j-1],labco->L[i-1][j+1],labco->L[i+1][j-1],labco->L[i+1][j+1],tmL[i][j]);//3x3 + } + } + for(int i = borderL; i < hei-borderL; i++ ) { + for(int j = borderL; j < wid-borderL; j++) { + labco->L[i][j] = tmL[i][j]; + } + } + + for (int i=0; iW * labco->H; + + int levwavL = levwav; + bool ref0=false; + if((cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f || cp.lev3s > 0.f) && cp.noiseena) ref0=true; + + // printf("LevwavL before: %d\n",levwavL); + if(cp.contrast == 0.f && cp.tonemap==false && cp.conres == 0.f && cp.conresH == 0.f && cp.val ==0 && !ref0 && params->wavelet.CLmethod=="all") { // no processing of residual L or edge=> we probably can reduce the number of levels + while(levwavL > 0 && cp.mul[levwavL-1] == 0.f) // cp.mul[level] == 0.f means no changes to level + levwavL--; + } + // printf("LevwavL after: %d\n",levwavL); + // if(cp.noiseena){ + if(levwavL < 4 ) levwavL=4;//to allow edge => I always allocate 3 (4) levels..because if user select wavelet it is to do something !! + // } + // else { + // if(levwavL < 3) levwavL=3;//to allow edge => I always allocate 3 (4) levels..because if user select wavelet it is to do something !! + // } + if(levwavL > 0) { + wavelet_decomposition* Ldecomp = new wavelet_decomposition (labco->data, labco->W, labco->H, levwavL, 1, skip, max(1,wavNestedLevels), DaubLen ); + if(!Ldecomp->memoryAllocationFailed) { + + float madL[8][3]; + bool memoryAllocationFailed = false; +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for schedule(dynamic) collapse(2) num_threads(wavNestedLevels) if(wavNestedLevels>1) +#endif + for (int lvl=0; lvl<4; lvl++) { + for (int dir=1; dir<4; dir++) { + int Wlvl_L = Ldecomp->level_W(lvl); + int Hlvl_L = Ldecomp->level_H(lvl); + + float ** WavCoeffs_L = Ldecomp->level_coeffs(lvl); + + madL[lvl][dir-1] = SQR(Mad(WavCoeffs_L[dir], Wlvl_L*Hlvl_L)); + } + } + int ind=0; + bool ref=false; + if((cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f || cp.lev3s > 0.f) && cp.noiseena) ref=true; + bool contr=false; + for(int f=0;f 0 || ref || contr) {//edge + Evaluate2(*Ldecomp, cp, ind, mean, meanN, sigma, sigmaN, MaxP, MaxN, madL); + } + //init for edge and denoise + float vari[4]; + + vari[0]=8.f*SQR((cp.lev0n/125.0)*(1.0+ cp.lev0n/25.0)); + vari[1]=8.f*SQR((cp.lev1n/125.0)*(1.0+ cp.lev1n/25.0)); + vari[2]=8.f*SQR((cp.lev2n/125.0)*(1.0+ cp.lev2n/25.0)); + vari[3]=8.f*SQR((cp.lev3n/125.0)*(1.0+ cp.lev3n/25.0)); + int edge=1; + if((cp.lev0n > 0.1f || cp.lev1n > 0.1f || cp.lev2n > 0.1f || cp.lev3n > 0.1f) && cp.noiseena) { + vari[0] = max(0.0001f,vari[0]); + vari[1] = max(0.0001f,vari[1]); + vari[2] = max(0.0001f,vari[2]); + vari[3] = max(0.0001f,vari[3]); + float* noisevarlum = NULL; // we need a dummy to pass it to WaveletDenoiseAllL + if(!WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, vari, edge))// + memoryAllocationFailed = true; + } + ind=1; + //Flat curve for Contrast=f(H) in levels + FlatCurve* ChCurve = NULL;//curve C=f(H) + bool Chutili = false; + ChCurve = new FlatCurve(params->wavelet.Chcurve); + if (!ChCurve || ChCurve->isIdentity()) { + if (ChCurve) { + delete ChCurve; + ChCurve = NULL; + } + } else + Chutili = true; + + + WaveletcontAllL(labco, varhue, varchro, *Ldecomp, cp, skip, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, waOpacityCurveWL, ChCurve, Chutili); + if(cp.val > 0 || ref || contr || cp.diagcurv) {//edge + Evaluate2(*Ldecomp, cp, ind, mean, meanN, sigma, sigmaN, MaxP, MaxN, madL); + } + WaveletcontAllLfinal(labco, varhue, varchro, *Ldecomp, cp, skip, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavCLVCcurve, waOpacityCurveWL, ChCurve, Chutili); + //Evaluate2(*Ldecomp, cp, ind, mean, meanN, sigma, sigmaN, MaxP, MaxN, madL); + + Ldecomp->reconstruct(labco->data, cp.strength); + } + delete Ldecomp; + } + //Flat curve for H=f(H) in residual image + FlatCurve* hhCurve = NULL;//curve H=f(H) + bool hhutili = false; + hhCurve = new FlatCurve(params->wavelet.hhcurve); + if (!hhCurve || hhCurve->isIdentity()) { + if (hhCurve) { + delete hhCurve; + hhCurve = NULL; + } + } else + hhutili = true; + + + if(!hhutili) {//always a or b + int levwava = levwav; + // printf("Levwava before: %d\n",levwava); + if(cp.chrores == 0.f && params->wavelet.CLmethod=="all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels + while(levwava > 0 && !cp.diag &&(((cp.CHmet==2 && (cp.chro == 0.f || cp.mul[levwava-1] == 0.f )) || (cp.CHmet!=2 && (levwava == 10 || (!cp.curv || (cp.curv && cp.mulC[levwava-1] == 0.f)))))) && (!cp.opaRG || levwava == 10 || (cp.opaRG && cp.mulopaRG[levwava-1] == 0.f)) && ((levwava == 10 ||(cp.CHSLmet==1 && cp.mulC[levwava-1] == 0.f)))) { + levwava--; + } + } + //printf("Levwava after: %d\n",levwava); + if(levwava > 0) { + wavelet_decomposition* adecomp = new wavelet_decomposition (labco->data+datalen, labco->W, labco->H,levwava, 1, skip, max(1,wavNestedLevels), DaubLen ); + if(!adecomp->memoryAllocationFailed) { + WaveletcontAllAB(labco, varhue, varchro, *adecomp, waOpacityCurveW, cp, true); + adecomp->reconstruct(labco->data+datalen, cp.strength); + } + delete adecomp; + } + int levwavb = levwav; + //printf("Levwavb before: %d\n",levwavb); + if(cp.chrores == 0.f && params->wavelet.CLmethod=="all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels + while(levwavb > 0 && !cp.diag && (((cp.CHmet==2 && (cp.chro == 0.f || cp.mul[levwavb-1] == 0.f )) || (cp.CHmet!=2 && (levwavb == 10 || (!cp.curv || (cp.curv && cp.mulC[levwavb-1] == 0.f)))))) && (!cp.opaBY || levwavb == 10 || (cp.opaBY && cp.mulopaBY[levwavb-1] == 0.f)) && ((levwavb == 10 ||(cp.CHSLmet==1 && cp.mulC[levwavb-1] == 0.f)))) { + levwavb--; + } + } + // printf("Levwavb after: %d\n",levwavb); + if(levwavb > 0) { + wavelet_decomposition* bdecomp = new wavelet_decomposition (labco->data+2*datalen, labco->W, labco->H, levwavb, 1, skip, max(1,wavNestedLevels), DaubLen ); + if(!bdecomp->memoryAllocationFailed) { + WaveletcontAllAB(labco, varhue, varchro, *bdecomp, waOpacityCurveW, cp, false); + bdecomp->reconstruct(labco->data+2*datalen, cp.strength); + } + delete bdecomp; + } + } else {// a and b + int levwavab = levwav; + // printf("Levwavab before: %d\n",levwavab); + if(cp.chrores == 0.f && !hhutili && params->wavelet.CLmethod=="all") { // no processing of residual ab => we probably can reduce the number of levels + while(levwavab > 0 && (((cp.CHmet==2 && (cp.chro == 0.f || cp.mul[levwavab-1] == 0.f )) || (cp.CHmet!=2 && (levwavab == 10 || (!cp.curv || (cp.curv && cp.mulC[levwavab-1] == 0.f)))))) && (!cp.opaRG || levwavab == 10 || (cp.opaRG && cp.mulopaRG[levwavab-1] == 0.f)) && ((levwavab == 10 ||(cp.CHSLmet==1 && cp.mulC[levwavab-1] == 0.f)))) { + levwavab--; + } + } + // printf("Levwavab after: %d\n",levwavab); + if(levwavab > 0) { + wavelet_decomposition* adecomp = new wavelet_decomposition (labco->data+datalen, labco->W, labco->H,levwavab, 1, skip, max(1,wavNestedLevels), DaubLen ); + wavelet_decomposition* bdecomp = new wavelet_decomposition (labco->data+2*datalen, labco->W, labco->H, levwavab, 1, skip, max(1,wavNestedLevels), DaubLen ); + if(!adecomp->memoryAllocationFailed && !bdecomp->memoryAllocationFailed) { + WaveletcontAllAB(labco, varhue, varchro, *adecomp, waOpacityCurveW, cp, true); + WaveletcontAllAB(labco, varhue, varchro, *bdecomp, waOpacityCurveW, cp, false); + WaveletAandBAllAB(labco, varhue, varchro, *adecomp, *bdecomp, cp, waOpacityCurveW, hhCurve, hhutili ); + + adecomp->reconstruct(labco->data+datalen, cp.strength); + bdecomp->reconstruct(labco->data+2*datalen, cp.strength); + + } + delete adecomp; + delete bdecomp; + } + } + if (hhCurve) + delete hhCurve; + + if(numtiles > 1 || (numtiles == 1 /*&& cp.avoi*/)) {//in all case since I add contrast curve + //calculate mask for feathering output tile overlaps + float Vmask[height+overlap] ALIGNED16; + float Hmask[width+overlap] ALIGNED16; + + if(numtiles > 1) { + for (int i=0; i0) Vmask[i] = mask; + if (tilebottom0) Hmask[i] = mask; + if (tilerighttoneCurve.hrenabled; + +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for schedule(dynamic,16) num_threads(wavNestedLevels) if(wavNestedLevels>1) +#endif + for (int i=tiletop; ia[i1][col]); + bv = LVFU(labco->b[i1][col]); + _mm_store_ps(&atan2Buffer[col],xatan2f(bv,av)); + + cv = _mm_sqrt_ps(SQRV(av)+SQRV(bv)); + yv = av / cv; + xv = bv / cv; + xyMask = vmaskf_eq(zerov, cv); + yv = vself(xyMask, onev, yv); + xv = vself(xyMask, zerov, xv); + _mm_store_ps(&yBuffer[col],yv); + _mm_store_ps(&xBuffer[col],xv); + _mm_store_ps(&chprovBuffer[col], cv / c327d68v); + + } + for(;cola[i1][col]; + float b = labco->b[i1][col]; + atan2Buffer[col] = xatan2f(b,a); + float Chprov1=sqrtf(SQR(a) + SQR(b)); + yBuffer[col] = (Chprov1 == 0.f) ? 1.f : a/Chprov1; + xBuffer[col] = (Chprov1 == 0.f) ? 0.f : b/Chprov1; + chprovBuffer[col] = Chprov1/327.68; + } + } +#endif + + for (int j=tileleft; ja[i1][j1]; + b = labco->b[i1][j1]; + float HH=xatan2f(b,a); + float Chprov1=sqrtf(SQR(a) + SQR(b)); + float2 sincosv; + sincosv.y = (Chprov1==0.0f) ? 1.f : a/(Chprov1); + sincosv.x = (Chprov1==0.0f) ? 0.f : b/(Chprov1); + Chprov1 /= 327.68f; +#endif + L = labco->L[i1][j1]; + const float Lin=labco->L[i1][j1]; + + if(wavclCurve && cp.finena) {labco->L[i1][j1] =(0.5f*Lin + 1.5f*wavclCurve[Lin])/2.f;}//apply contrast curve + L = labco->L[i1][j1]; + + float Lprov1=L/327.68f; + float Lprov2 = Lold[i][j]/327.68f; + float memChprov=varchro[i1][j1]; + float R,G,B; +#ifdef _DEBUG + bool neg=false; + bool more_rgb=false; + Color::gamutLchonly(HH,sincosv, Lprov1,Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); +#else + Color::gamutLchonly(HH,sincosv, Lprov1,Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); +#endif + L=Lprov1*327.68f; + + a=327.68f*Chprov1*sincosv.y;//gamut + b=327.68f*Chprov1*sincosv.x;//gamut + float correctionHue=0.0f; // Munsell's correction + float correctlum=0.0f; + Lprov1=L/327.68f; + float Chprov=sqrtf(SQR(a)+ SQR(b))/327.68f; +#ifdef _DEBUG + Color::AllMunsellLch(true, Lprov1,Lprov2,HH,Chprov,memChprov,correctionHue,correctlum, MunsDebugInfo); +#else + Color::AllMunsellLch(true, Lprov1,Lprov2,HH,Chprov,memChprov,correctionHue,correctlum); +#endif + + if(correctionHue!=0.f || correctlum!=0.f) { // only calculate sin and cos if HH changed + if(fabs(correctionHue) < 0.015f) + HH+=correctlum; // correct only if correct Munsell chroma very little. + sincosv = xsincosf(HH+correctionHue); + } + + a=327.68f*Chprov*sincosv.y;// apply Munsell + b=327.68f*Chprov*sincosv.x;//aply Munsell + } else {//general case + L = labco->L[i1][j1]; + const float Lin=labco->L[i1][j1]; + + if(wavclCurve && cp.finena) {labco->L[i1][j1] = (0.5f*Lin + 1.5f*wavclCurve[Lin])/2.f;}//apply contrast curve + L = labco->L[i1][j1]; + a = labco->a[i1][j1]; + b = labco->b[i1][j1]; + } + if(numtiles > 1) { + float factor = Vmask[i1]*Hmask[j1]; + dsttmp->L[i][j]+= factor*L; + dsttmp->a[i][j]+= factor*a; + dsttmp->b[i][j]+= factor*b; + } else { + dsttmp->L[i][j] = L; + dsttmp->a[i][j] = a; + dsttmp->b[i][j] = b; + + } + } + } + } + if(LoldBuffer != NULL) { + delete [] LoldBuffer; + delete [] Lold; + } + if(numtiles>1) + delete labco; + } + } + for (int i=0; i 1) { + dst->CopyFrom(dsttmp); + delete dsttmp; + } + + if (settings->verbose) { + t2e.set(); + printf("Wavelet performed in %d usec:\n", t2e.etime(t1e)); + } + +}//end o + + + + +#undef TS +#undef fTS +#undef offset +#undef epsilon + + void ImProcFunctions::Aver( float * RESTRICT DataList, int datalen, float &averagePlus, float &averageNeg, float &max, float &min) { + + //find absolute mean + int countP = 0, countN = 0; + float averaP = 0.f, averaN = 0.f; + + float thres = 5.f;//different fom zero to take into account only data large enough + max=0.f; + min=0.f; +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) +#endif +{ + float lmax = 0.f, lmin = 0.f; +#ifdef _RT_NESTED_OPENMP +#pragma omp for reduction(+:averaP,averaN,countP,countN) nowait +#endif + for(int i=0;i= thres) { + averaP += DataList[i]; + if(DataList[i]> lmax) + lmax = DataList[i]; + countP++; + } + else if(DataList[i] < -thres) { + averaN += DataList[i]; + if(DataList[i] < lmin) + lmin = DataList[i]; + countN++; + } + } +#ifdef _RT_NESTED_OPENMP +#pragma omp critical +#endif +{ + max = max > lmax ? max : lmax; + min = min < lmin ? min : lmin; +} +} + + averagePlus=averaP/countP; + averageNeg=averaN/countN; + + } + + + void ImProcFunctions::Sigma( float * RESTRICT DataList, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg) { + int countP = 0, countN = 0; + float variP = 0.f, variN = 0.f; + float thres = 5.f;//different fom zero to take into account only data large enough + +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for reduction(+:variP,variN,countP,countN) num_threads(wavNestedLevels) if(wavNestedLevels>1) +#endif + for(int i=0;i= thres) { + variP += SQR(DataList[i] - averagePlus); + countP++; + } + else if(DataList[i] <= -thres) { + variN += SQR(DataList[i] - averageNeg); + countN++; + } + } + + sigmaPlus=sqrt(variP/countP); + sigmaNeg=sqrt(variN/countN); + + } + + void ImProcFunctions::Evaluate2(wavelet_decomposition &WaveletCoeffs_L, + struct cont_params cp, int ind, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, float madL[8][3]){ +//StopWatch Stop1("Evaluate2"); + int maxlvl = WaveletCoeffs_L.maxlevel(); + for (int lvl=0; lvlwavelet.thres; + for (int dir=1; dir<4; dir++) { + Aver(WavCoeffs_L[dir], W_L*H_L, avLP[dir], avLN[dir], maxL[dir], minL[dir]); + Sigma(WavCoeffs_L[dir], W_L*H_L, avLP[dir], avLN[dir], sigP[dir], sigN[dir]); + // printf("dir=%d level=%d avLP=%f max=%f avLN=%f min=%f sigP=%f sigN=%f\n",dir,level,avLP[dir] ,maxL[dir], avLN[dir] ,minL[dir], sigP[dir], sigN[dir]); + } + AvL=0.f;AvN=0.f;SL=0.f;SN=0.f;maxLP=0.f;maxLN=0.f;MADL=0.f; + for (int dir=1; dir<4; dir++) { + AvL +=avLP[dir]; + AvN +=avLN[dir]; + SL +=sigP[dir]; + SN +=sigN[dir]; + maxLP += maxL[dir]; + maxLN += minL[dir]; + MADL += madL[dir]; + } + AvL/=3; + AvN/=3; + SL/=3; + SN/=3; + maxLP/=3; + maxLN/=3; + MADL/=3; + if(level < 4) MADL=sqrt(MADL);else MADL=0.f; + mean[level]=AvL; + meanN[level]=AvN; + sigma[level]=SL; + sigmaN[level]=SN; + MaxP[level]=maxLP; + MaxN[level]=maxLN; + // if(params->wavelet.CLmethod!="all") {//display only if user choose different from all + // printf("Ind=%d Level=%d MadL=%f AvL=%f AvN=%f SL=%f SN=%f maxP=%f maxN=%f\n",ind, level,MADL,mean[level],meanN[level],sigma[level],sigmaN[level],MaxP[level],MaxN[level]); + // } + } + +float *ImProcFunctions::ContrastDR(float *Source, int skip, struct cont_params &cp, int W_L, int H_L, float Compression,float DetailBoost,float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx, float *Contrast){ + int n=W_L*H_L; + if(Contrast == NULL) Contrast = new float[n]; + memcpy(Contrast, Source, n*sizeof(float)); +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for +#endif + for (int i=0; i ave) { + float kh = ah*(Source[i]*100.f)+bh; + prov=32768.f*Source[i]; + Contrast[i]=ave+kh*(Source[i]*32768.f-ave); + } else { + float kl = al*(Source[i]*100.f)+bl; + prov=32768.f*Source[i]; + Contrast[i]=ave-kl*(ave-Source[i]*32768.f); + } + float diflc=Contrast[i]-prov; + diflc*=factorx; + Contrast[i] = (prov + diflc)/32768.f; + //contrast between 0 and 1 + } +*/ + Contrast[i] = Source[i] ; + + } + return Contrast; +} + +SSEFUNCTION float *ImProcFunctions::CompressDR(float *Source, int skip, struct cont_params &cp, int W_L, int H_L, float Compression,float DetailBoost,float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx, float *Compressed){ + + const float eps = 0.000001f; + int n=W_L*H_L; + +#ifdef __SSE2__ +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel +#endif +{ + __m128 epsv = _mm_set1_ps( eps ); +#ifdef _RT_NESTED_OPENMP +#pragma omp for +#endif + for(int ii = 0; ii < n-3; ii+=4) + _mm_storeu_ps( &Source[ii], xlogf(LVFU(Source[ii]) + epsv)); +} + for(int ii = n-(n%4); ii < n; ii++) + Source[ii] = xlogf(Source[ii] + eps); + +#else +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for +#endif + for(int ii = 0; ii < n; ii++) + Source[ii] = xlogf(Source[ii] + eps); +#endif + + float *ucr =ContrastDR(Source, skip, cp, W_L, H_L, Compression,DetailBoost,max0, min0, ave, ah, bh, al, bl, factorx); + if(Compressed == NULL) Compressed = ucr; + float temp; + if(DetailBoost>0.f && DetailBoost < 0.05f ) { + float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2) + temp = 1.2f*xlogf( -betemp); + temp /= 20.f; + } + else if(DetailBoost>=0.05f && DetailBoost < 0.25f ) { + float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2) + temp = 1.2f*xlogf( -betemp); + temp /= (-75.f*DetailBoost+23.75f); + } + else if(DetailBoost>=0.25f) { + float betemp=expf(-(2.f-DetailBoost+0.694f))-1.f;//0.694 = log(2) + temp = 1.2f*xlogf( -betemp); + temp /= (-2.f*DetailBoost + 5.5f); + } + + else temp= (Compression - 1.0f)/20.f; +// printf("temp=%f \n", temp); + + +#ifdef __SSE2__ +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel +#endif +{ + __m128 cev, uev, sourcev; + __m128 epsv = _mm_set1_ps( eps ); + __m128 DetailBoostv = _mm_set1_ps( DetailBoost ); + __m128 tempv = _mm_set1_ps( temp ); +#ifdef _RT_NESTED_OPENMP +#pragma omp for +#endif + for(int i = 0; i < n-3; i+=4){ + cev = xexpf(LVFU(Source[i]) + LVFU(ucr[i])*(tempv)) - epsv; + uev = xexpf(LVFU(ucr[i])) - epsv; + sourcev = xexpf(LVFU(Source[i])) - epsv; + _mm_storeu_ps( &Source[i], sourcev); + _mm_storeu_ps( &Compressed[i], cev + DetailBoostv * (sourcev - uev) ); + } +} + for(int i=n-(n%4); i < n; i++){ + float ce = xexpf(Source[i] + ucr[i]*(temp)) - eps; + float ue = xexpf(ucr[i]) - eps; + Source[i] = xexpf(Source[i]) - eps; + Compressed[i] = ce + DetailBoost*(Source[i] - ue); + } + +#else +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for +#endif + for(int i = 0; i < n; i++){ + float ce = xexpf(Source[i] + ucr[i]*(temp)) - eps; + float ue = xexpf(ucr[i]) - eps; + Source[i] = xexpf(Source[i]) - eps; + Compressed[i] = ce + DetailBoost*(Source[i] - ue); + } +#endif + + if(Compressed != ucr) delete[] ucr; + return Compressed; + + +} + +void ImProcFunctions::ContrastResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, struct cont_params &cp, int W_L, int H_L, float max0, float min0, float ave, float ah, float bh, float al, float bl, float factorx) { + float stren=cp.tmstrength; + float gamm=params->wavelet.gamma; + cp.TMmeth=2;//default after testing + if(cp.TMmeth ==1) {min0 = 0.0f;max0=32768.f;} + else if (cp.TMmeth ==2) {min0 = 0.0f;} +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for +#endif + for(int i = 0; i < W_L*H_L; i++) + { WavCoeffs_L0[i]= (WavCoeffs_L0[i] - min0)/max0; + WavCoeffs_L0[i]*=gamm; + } + + float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. + float DetailBoost = stren; + if(stren < 0.0f) DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing. + + + CompressDR(WavCoeffs_L0, skip, cp, W_L, H_L, Compression,DetailBoost,max0, min0, ave, ah, bh, al, bl, factorx, WavCoeffs_L0); + + +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for // removed schedule(dynamic,10) +#endif + for(int ii = 0; ii < W_L*H_L; ii++) + WavCoeffs_L0[ii] = WavCoeffs_L0[ii]*max0*(1.f/gamm) + min0; + } + + + + + void ImProcFunctions::EPDToneMapResid(float * WavCoeffs_L0, unsigned int Iterates, int skip, struct cont_params cp, int W_L, int H_L, float max0, float min0) { + + + float stren=cp.tmstrength; + float edgest=params->epd.edgeStopping; + float sca=params->epd.scale; + float gamm=params->wavelet.gamma; + float rew=params->epd.reweightingIterates; + EdgePreservingDecomposition epd2 = EdgePreservingDecomposition(W_L, H_L); + cp.TMmeth=2;//default after testing + if(cp.TMmeth ==1) {min0 = 0.0f;max0=32768.f;} + else if (cp.TMmeth ==2) {min0 = 0.0f;} + // max0=32768.f; +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for +#endif + for(int i = 0; i < W_L*H_L; i++) + { WavCoeffs_L0[i]= (WavCoeffs_L0[i] - min0)/max0; + WavCoeffs_L0[i]*=gamm; + } + + float Compression = expf(-stren); //This modification turns numbers symmetric around 0 into exponents. + float DetailBoost = stren; + if(stren < 0.0f) DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing. + + //Auto select number of iterates. Note that p->EdgeStopping = 0 makes a Gaussian blur. + if(Iterates == 0) Iterates = (unsigned int)(edgest*15.0f); + + + epd2.CompressDynamicRange(WavCoeffs_L0, (float)sca/skip, edgest, Compression, DetailBoost, Iterates, rew, WavCoeffs_L0); + + //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel for // removed schedule(dynamic,10) +#endif + for(int ii = 0; ii < W_L*H_L; ii++) + WavCoeffs_L0[ii] = WavCoeffs_L0[ii]*max0*(1.f/gamm) + min0; + } + +void ImProcFunctions::WaveletcontAllLfinal(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_L, + struct cont_params &cp, int skip, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveWL & waOpacityCurveWL, FlatCurve* ChCurve, bool Chutili){ + + int maxlvl = WaveletCoeffs_L.maxlevel(); + int W_L = WaveletCoeffs_L.level_W(0); + int H_L = WaveletCoeffs_L.level_H(0); + float * WavCoeffs_L0 = WaveletCoeffs_L.coeff0; + + +#ifdef _RT_NESTED_OPENMP +#pragma omp for schedule(dynamic) collapse(2) +#endif + for (int dir=1; dir<4; dir++) { + for (int lvl=0; lvl1) +#endif + for (int i=0; i1) +#endif +{ + float lminL = FLT_MAX; + float lmaxL = 0.f; + +#ifdef _RT_NESTED_OPENMP +#pragma omp for +#endif + for(int i = 0; i < W_L*H_L; i++) { + if(WavCoeffs_L0[i] < lminL) lminL = WavCoeffs_L0[i]; + if(WavCoeffs_L0[i] > lmaxL) lmaxL = WavCoeffs_L0[i]; + + } +#ifdef _RT_NESTED_OPENMP +#pragma omp critical +#endif + { if(lminL < min0) min0 = lminL; + if(lmaxL > max0) max0 = lmaxL; + } + +} + + } + + // printf("MAXmax0=%f MINmin0=%f\n",max0,min0); + +//tone mapping +if(cp.tonemap && cp.contmet==2 && cp.resena) { + //iterate = 5 + EPDToneMapResid(WavCoeffs_L0, 5, skip, cp, W_L, H_L, max0, min0); + +} +//end tonemapping + + + max0/=327.68f; + min0/=327.68f; + float ave = avedbl / (double)(W_L*H_L); + float av=ave/327.68f; + float ah=(multH-1.f)/(av-max0);// + float bh=1.f-max0*ah; + float al=(multL-1.f)/(av-min0); + float bl=1.f-min0*al; + float factorx=1.f; +// float *koeLi[9]; +// float maxkoeLi[9]; + float *koeLi[12]; + float maxkoeLi[12]; + + float *koeLibuffer = NULL; + bool lipschitz =false; + lipschitz=true; + + if(lipschitz==true) { + for(int y=0;y<12;y++) maxkoeLi[y]=0.f;//9 + koeLibuffer = new float[12*H_L*W_L];//12 + for (int i=0; i<12; i++) {//9 + koeLi[i] = &koeLibuffer[i*W_L*H_L]; + } + + for(int j=0;j<12;j++)//9 + for (int i=0; i1) +#endif +{ + if(contrast != 0.f && cp.resena) { // contrast = 0.f means that all will be multiplied by 1.f, so we can skip this step + { +#ifdef _RT_NESTED_OPENMP +#pragma omp for +#endif + for (int i=0; i ave) { + float kh = ah*(WavCoeffs_L0[i]/327.68f)+bh; + prov=WavCoeffs_L0[i]; + WavCoeffs_L0[i]=ave+kh*(WavCoeffs_L0[i]-ave); + } else { + float kl = al*(WavCoeffs_L0[i]/327.68f)+bl; + prov=WavCoeffs_L0[i]; + WavCoeffs_L0[i]=ave-kl*(ave-WavCoeffs_L0[i]); + } + float diflc=WavCoeffs_L0[i]-prov; + diflc*=factorx; + WavCoeffs_L0[i] = prov + diflc; + } + } + } + } + +if(cp.tonemap && cp.contmet==1 && cp.resena) { + float maxp=max0*256.f; + float minp=min0*256.f; +#ifdef _RT_NESTED_OPENMP +#pragma omp single +#endif + ContrastResid(WavCoeffs_L0, 5, skip, cp, W_L, H_L, maxp, minp, ave, ah, bh, al, bl, factorx ); +} +#ifdef _RT_NESTED_OPENMP +#pragma omp barrier +#endif + + if((cp.conres != 0.f || cp.conresH != 0.f) && cp.resena) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step +#ifdef _RT_NESTED_OPENMP +#pragma omp for nowait +#endif + for (int i=0; i (100.f-tran)) + tran=100.f-cp.th; + if(LL100 < cp.th){ + float aalp=(1.f-alp)/cp.th;//no changes for LL100 = cp.th + float kk=aalp*LL100+alp; + WavCoeffs_L0[i] *= (1.f+kk*cp.conres/200.f); + } + else if(LL100 < cp.th + tran) { + float ath = -cp.conres/tran; + float bth = cp.conres-ath*cp.th; + WavCoeffs_L0[i] *= (1.f+(LL100*ath+bth)/200.f); + } + //highlight + tran=5.f; + if(cp.thH < (tran)) + tran = cp.thH; + if(LL100 > cp.thH) + WavCoeffs_L0[i] *= (1.f+cp.conresH/200.f); + else if(LL100 > (cp.thH - tran)) { + float athH = cp.conresH/tran; + float bthH = cp.conresH-athH*cp.thH; + WavCoeffs_L0[i] *= (1.f+(LL100*athH+bthH)/200.f); + } + } + } + //enabled Lipschitz..replace simple by complex edge detection + // I found this concept on the web (doctoral thesis on medical Imaging) + // I was inspired by the principle of Canny and Lipschitz (continuity and derivability) + // I adapted the principle but have profoundly changed the algorithm + // One can 1) change all parameters and found good parameters; + //one can also chnage in calckoe + float edd=settings->ed_detec; + float eddlow=settings->ed_low;//5 to 40 + // float eddlipinfl=settings->ed_lipinfl; + // float eddlipampl=settings->ed_lipampl; + float eddlipinfl=0.005f*cp.edgsens + 0.4f; + float eddlipampl=1.f + cp.edgampl/50.f; + // float eddlow=5.f + cp.edgampl/2.f;//settings->ed_low;//5 to 40 + + +if(cp.detectedge && lipschitz==true) { //enabled Lipschitz control...more memory..more time... + float *tmCBuffer = new float[H_L*W_L]; + float *tmC[H_L]; + for (int i=0; i 1 for alp >eddlipinfl and alph < 1 + //Liamp < 1 for alp < eddlipinfl and alph > 0 + if(alph > 1.f) {alph = 1.f/ alph;} + if(beta > 1.f) {beta=1.f/beta;} + //take into account diagonal + //if in same value OK + //if not no edge or reduction + float bet=1.f; + //if(cp.lip3) {//enhance algorithm + if(alph > eddlipinfl && beta < 0.85f*eddlipinfl) {//0.85 arbitrary value ==> eliminate from edge if H V D too different + bet=beta; + } + //} + float AmpLip=1.f; + + if(alph > eddlipinfl) {AmpLip=alipinfl*alph+blipinfl;kampli=SQR(bet)*AmpLip*aamp;}//If beta low reduce kampli + else {AmpLip=(1.f/eddlipinfl)*SQR(SQR(alph*bet));kampli=AmpLip/aamp;}//Strong Reduce if beta low + // comparaison betwwen pixel and neighbours to do ==> I think 3 dir above is better + /* if(cp.lip3){ + koeLi[lvl*3][i*W_L + j] = (koeLi[lvl*3][i*W_L + j] + koeLi[lvl*3][(i-1)*W_L + j] + koeLi[lvl*3][(i+1)*W_L + j] + + koeLi[lvl*3][i*W_L + j+1] + koeLi[lvl*3][i*W_L + j-1] + koeLi[lvl*3][(i-1)*W_L + j-1] + + koeLi[lvl*3][(i-1)*W_L + j+1] +koeLi[lvl*3][(i+1)*W_L + j-1] +koeLi[lvl*3][(i+1)*W_L + j+1])/9.f; + } + */ + // apply to each direction Wavelet level : horizontal / vertiacle / diagonal + //interm += SQR(koeLi[lvl*3 + dir-1][i*W_L + j]); + + interm*=kampli; + if(interm < cp.eddetthr/eddlow) interm = 0.01f;//eliminate too low values + //we can change this part of algo==> not equal but ponderate + koeLi[lvl*3][i*W_L + j]=koeLi[lvl*3 + 1][i*W_L + j]=koeLi[lvl*3 + 2][i*W_L + j]=interm;//new value + //here KoeLi contains values where gradient is high and coef high, and eliminate low values... + } + } + } + // end +} + +#ifdef _RT_NESTED_OPENMP +#pragma omp for schedule(dynamic) collapse(2) +#endif + for (int dir=1; dir<4; dir++) { + for (int lvl=0; lvl1) +#endif +{ +#ifdef __SSE2__ + float huebuffer[W_L] ALIGNED64; + float chrbuffer[W_L] ALIGNED64; +#endif // __SSE2__ +#ifdef _RT_NESTED_OPENMP +#pragma omp for schedule(dynamic,16) +#endif + for (int i=0; iv(i,j) = valpar; + } + */ + float valparam = float((hhCurve->getVal(Color::huelab_to_huehsv2(hueR))-0.5f) * 1.7f) +hueR;//get H=f(H) 1.7 optimisation ! + float2 sincosval = xsincosf(valparam); + WavCoeffs_a0[i*W_L+j]=chR*sincosval.y; + WavCoeffs_b0[i*W_L+j]=chR*sincosval.x; + } + } +} + } + +} + + void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_ab,const WavOpacityCurveW & waOpacityCurveW, + struct cont_params &cp, const bool useChannelA){ + + int maxlvl = WaveletCoeffs_ab.maxlevel(); + int W_L = WaveletCoeffs_ab.level_W(0); + int H_L = WaveletCoeffs_ab.level_H(0); + + float * WavCoeffs_ab0 = WaveletCoeffs_ab.coeff0; + +#ifdef _RT_NESTED_OPENMP +#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) +#endif +{ + if(cp.chrores != 0.f && cp.resena) { // cp.chrores == 0.f means all will be multiplied by 1.f, so we can skip the processing of residual + +#ifdef _RT_NESTED_OPENMP +#pragma omp for nowait +#endif + for (int i=0; i 0.f){ + if((modhue < cp.t_ry && modhue > cp.t_ly)) { + scale=(100.f-cp.sky)/100.1f; + } else if((modhue >= cp.t_ry && modhue < cp.b_ry)) { + scale=(100.f-cp.sky)/100.1f; + float ar=(scale-1.f)/(cp.t_ry- cp.b_ry); + float br=scale-cp.t_ry*ar; + scale=ar*modhue+br; + } else if((modhue > cp.b_ly && modhue < cp.t_ly)) { + scale=(100.f-cp.sky)/100.1f; + float al=(scale-1.f)/(-cp.b_ly + cp.t_ly); + float bl=scale-cp.t_ly*al; + scale=al*modhue+bl; + } + } else if(skyprot < 0.f){ + if((modhue > cp.t_ry || modhue < cp.t_ly)){ + scale=(100.f+cp.sky)/100.1f; + } + /* else if((modhue >= cp.t_ry && modhue < cp.b_ry)) { + scale=(100.f+cp.sky)/100.1f; + float ar=(scale-1.f)/(cp.t_ry- cp.b_ry); + float br=scale-cp.t_ry*ar; + scale=ar*modhue+br; + } + else if((modhue > cp.b_ly && modhue < cp.t_ly)) { + scale=(100.f+cp.sky)/100.1f; + float al=(scale-1.f)/(-cp.b_ly + cp.t_ly); + float bl=scale-cp.t_ly*al; + scale=al*modhue+bl; + } + */ + } + WavCoeffs_ab0[i]*=(1.f+cp.chrores*(scale)/100.f); + + } + } + + if(cp.cbena && cp.resena) {//if user select Toning and color balance + +#ifdef _RT_NESTED_OPENMP +#pragma omp for nowait +#endif + for (int i=0; iL[ii*2][jj*2])/327.68f;//I use labco but I can use also WavCoeffs_L0 (more exact but more memory) + + float sca=1.f;//amplifer - reducter...about 1, but perhaps 0.6 or 1.3 + if(useChannelA) {//green red (little magenta) + //transition to avoid artifacts with 6 between 30 to 36 and 63 to 69 + float aa=(cp.grmed-cp.grlow)/6.f; + float bb= cp.grlow-30.f*aa; + float aaa=(cp.grhigh-cp.grmed)/6.f; + float bbb= cp.grmed-63.f*aaa; + + if(LL < 30.f)//shadows + WavCoeffs_ab0[i]+=cp.grlow*(sca)*300.f; + else if(LL >= 30.f && LL < 36.f) {//transition + float tr=aa*LL+bb; + WavCoeffs_ab0[i]+= tr*(sca)*300.f; + } + else if(LL >= 36.f && LL < 63.f)//midtones + WavCoeffs_ab0[i]+=cp.grmed*(sca)*300.f; + else if(LL >= 63.f && LL < 69.f) {//transition + float trh=aaa*LL+bbb; + WavCoeffs_ab0[i]+=trh*(sca)*300.f; + } + else if(LL >= 69.f)//highlights + WavCoeffs_ab0[i]+=cp.grhigh*(sca)*300.f; + } + else {//blue yellow + //transition with 6 between 30 to 36 and 63 to 69 + float aa1=(cp.blmed-cp.bllow)/6.f; + float bb1= cp.bllow-30.f*aa1; + float aaa1=(cp.blhigh-cp.blmed)/6.f; + float bbb1= cp.blmed-63.f*aaa1; + + if(LL < 30.f) + WavCoeffs_ab0[i]+=cp.bllow*(sca)*300.f; + else if(LL >= 30.f && LL < 36.f) { + float tr1=aa1*LL+bb1; + WavCoeffs_ab0[i]+=tr1*(sca)*300.f; + } + else if(LL >= 36.f && LL < 63.f) + WavCoeffs_ab0[i]+=cp.blmed*(sca)*300.f; + else if(LL >= 63.f && LL < 69.f) { + float trh1=aaa1*LL+bbb1; + WavCoeffs_ab0[i]+=trh1*(sca)*300.f; + } + else if(LL >= 69.f) + WavCoeffs_ab0[i]+=cp.blhigh*(sca)*300.f; + } + } + } + +#ifdef _RT_NESTED_OPENMP +#pragma omp for schedule(dynamic) collapse(2) +#endif + for (int dir=1; dir<4; dir++) { + for (int lvl=0; lvl= 30.f && cp.eddetthr < 50.f) { + borderL = 1; + + for (int i=1; i= 50.f && cp.eddetthr < 75.f) { + borderL = 1; + for (int i=1; i= 75.f) { + borderL = 2; + //if(cp.lip3 && level > 1) { + if(level > 1) {// do not activate 5x5 if level 0 or 1 + + for (int i=2; i lees good results==> probably because structure data different and also I compare to original value which have + and - + for(int i = borderL; i < H_L-borderL; i++ ) {//[-1 0 1] x==>j + for(int j = borderL; j < W_L-borderL; j++) { + tmC[i][j]=- WavCoeffs_LL[dir][(i)*W_L + j-1] + WavCoeffs_LL[dir][(i)*W_L + j+1]; + } + } + for(int i = borderL; i < H_L-borderL; i++ ) {//[1 0 -1] y==>i + for(int j = borderL; j < W_L-borderL; j++) { + tmC[i][j]= - WavCoeffs_LL[dir][(i-1)*W_L + j] + WavCoeffs_LL[dir][(i+1)*W_L + j]; + } + } + */ + + float thr=40.f;//avoid artifact eg. noise...to test + float thr2=1.5f*edd;//edd can be modified in option ed_detect + thr2+=cp.eddet/30.f;//to test + float diffFactor = (cp.eddet/100.f); + for(int i = 0; i < H_L; i++ ) { + for(int j = 0; j < W_L; j++) { + koeLi[level*3 + dir-1][i*W_L + j]=1.f; + } + } + for(int i = borderL; i < H_L-borderL; i++ ) { + for(int j = borderL; j < W_L-borderL; j++) { + // my own algo : probably a little false, but simpler as Lipschitz ! + // Thr2 = maximum of the function ==> Lipsitch says = probably edge +// float temp = WavCoeffs_LL[dir][i*W_L + j]; +// if(temp>=0.f && temp < thr) temp = thr; +// if(temp < 0.f && temp > -thr) temp = -thr; + float temp = max(fabsf(WavCoeffs_LL[dir][i*W_L + j]), thr ); + koeLi[level*3 + dir-1][i*W_L + j]= min(thr2,fabs(tmC[i][j]/temp));// limit maxi + //it will be more complicated to calculate both Wh and Wv, but we have also Wd==> pseudo Lipschitz + if(koeLi[level*3+ dir-1][i*W_L + j] > maxkoeLi[level*3+ dir-1]) + maxkoeLi[level*3+ dir-1] = koeLi[level*3 + dir-1][i*W_L + j]; + float diff = maxkoeLi[level*3+ dir-1] - koeLi[level*3 + dir-1][i*W_L + j]; + diff *= diffFactor; + koeLi[level*3 + dir-1][i*W_L + j] = maxkoeLi[level*3 + dir-1] - diff; + } + } + +} + + void ImProcFunctions::finalContAllL (int maxlvl, LabImage * labco, float ** varhue, float **varchrom, float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params &cp, + int W_L, int H_L, int skip, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveWL & waOpacityCurveWL, FlatCurve* ChCurve, bool Chutili) + { + bool lipschitz=true; + float edge=1.f; + bool curvdiag=true; + if(curvdiag && cp.finena) {//curve + float insigma=0.666f;//SD + float logmax=log(MaxP[level]);//log Max + float rapX=(mean[level]+sigma[level])/MaxP[level];//rapport between sD / max + float inx=log(insigma); + float iny=log(rapX); + float rap=inx/iny;//koef + float asig=0.166f/sigma[level]; + float bsig=0.5f-asig*mean[level]; + float amean=0.5f/mean[level]; + float absciss; + float kinterm; + float kmul; + for (int i=0; i= (mean[level]+sigma[level])){//for max + float valcour=log(fabs(WavCoeffs_L[dir][i])); + float valc=valcour-logmax; + float vald=valc*rap; + absciss=exp(vald); + + } + else if(fabs(WavCoeffs_L[dir][i])>=mean[level] && fabs(WavCoeffs_L[dir][i]) < (mean[level]+sigma[level])){ + absciss=asig*fabs(WavCoeffs_L[dir][i])+bsig; + } + // else if(fabs(WavCoeffs_L[dir][i]) < mean[level]){ + else + absciss=amean*fabs(WavCoeffs_L[dir][i]); + // } + kinterm=1.f; + kmul=1.f; + + float kc = kmul*(waOpacityCurveWL[absciss*500.f]-0.5f); + float reduceeffect=1.5f; + if(kc <=0.f) reduceeffect=1.f; + kinterm = 1.f + reduceeffect*kmul*(waOpacityCurveWL[absciss*500.f]-0.5f); + + if(kinterm<0.f) kinterm=0.01f; + } + + WavCoeffs_L[dir][i] *= kinterm; + } + } + int choicelevel = atoi(params->wavelet.Lmethod.data())-1; + choicelevel = choicelevel == -1 ? 4 : choicelevel; + + int choiceClevel=0; + if(params->wavelet.CLmethod=="one") choiceClevel=0; + else if(params->wavelet.CLmethod=="inf") choiceClevel=1; + else if(params->wavelet.CLmethod=="sup") choiceClevel=2; + else if(params->wavelet.CLmethod=="all") choiceClevel=3; + int choiceDir=0; + if(params->wavelet.Dirmethod=="one") choiceDir=1; + else if(params->wavelet.Dirmethod=="two") choiceDir=2; + else if(params->wavelet.Dirmethod=="thr") choiceDir=3; + else if(params->wavelet.Dirmethod=="all") choiceDir=0; + + int dir1 = (choiceDir == 2) ? 1 : 2; + int dir2 = (choiceDir == 3) ? 1 : 3; + if(choiceClevel<3) { // not all levels visible, paint residual + if(level == 0) { + if(cp.backm!=2) { // nothing to change when residual is used as background + float backGroundColor = (cp.backm==1) ? 12000.f : 0.f; + for (int i=0; i= cp.maxilev) { + for (int dir=1; dir<4; dir++) { + for (int i=0; i choicelevel) { + for (int dir=1; dir<4; dir++) { + for (int i=0; i= choicelevel + if(level > choicelevel) { + for (int i=0; i= choicelevel + if(choicelevel >= cp.maxilev) { + for (int dir=1; dir<4; dir++) { + for (int i=0; itop_right; + float t_l=settings->top_left; + float b_r=settings->bot_right; + float b_l=settings->bot_left; + float edd=settings->ed_detec; + float eddlow=settings->ed_low; + float eddstrength=settings->ed_detecStr; + float aedstr=(eddstrength-1.f)/90.f; + float bedstr=1.f-10.f*aedstr; + + bool refi=false; + // if(cp.lev0s > 0.f || cp.lev1s > 0.f || cp.lev2s > 0.f) refi=true; + // if(cp.val > 0 || refi) {//edge + if(cp.val > 0 && cp.edgeena) { + float * koe; + float maxkoe=0.f; + if(lipschitz==false) { + koe = new float [H_L*W_L]; + for (int i=0; i=0.f && temp < thr) temp= thr; + if(temp < 0.f && temp > -thr) temp= -thr; + koe[i*W_L + j]= min(thr2,fabs(tmC[i][j]/temp)); + + if(koe[i*W_L + j] > maxkoe) maxkoe=koe[i*W_L + j]; + float diff=maxkoe-koe[i*W_L + j]; + diff *=(cp.eddet/100.f); + float interm=maxkoe-diff; + if(interm < cp.eddetthr/30.f) interm = 0.01f; + + koe[i*W_L + j]=interm; + + } + } + //printf("maxkoe=%f \n",maxkoe); + + for (int i=0; i not too high value to avoid artifacts + float value = ((float)cp.val)/8.f;//strength + if (scaleskip[1] < 1.f) value *= (atten01234*scaleskip[1]);//for zoom < 100% reduce strength...I choose level 1...but!! + float edge=1.f; + float lim0=20.f;//arbitrary limit for low radius and level between 2 or 3 to 30 maxi + float lev = float (level); + float repart=(float)cp.til; + float brepart; + if(cp.reinforce==1) brepart=3.f; + if(cp.reinforce==3) brepart=0.5f; //arbitrary value to increase / decrease repart, between 1 and 0 + float arepart=-(brepart-1.f)/(lim0/60.f); + if (cp.reinforce !=2) {if(rad < lim0/60.f) repart *= (arepart*rad + brepart);}//linear repartition of repart + + float al0 = 1.f + (repart)/50.f; + float al10 =1.0f;//arbitrary value ==> less = take into account high levels + // float ak =-(al0-al10)/10.f;//10 = maximum levels + float ak =-(al0-al10)/10.f;//10 = maximum levels + float bk =al0; + float koef = ak*level+bk;//modulate for levels : more levels high, more koef low ==> concentrated action on low levels, without or near for high levels + float expkoef= -pow(fabs(rad - lev),koef);//reduce effect for high levels + if (cp.reinforce==3) {if(rad < lim0/60.f && level==0) expkoef *= repart;}//reduce effect for low values of rad and level=0==> quasi only level 1 is effective + if (cp.reinforce==1) {if(rad < lim0/60.f && level==1) expkoef /= repart;}//increase effect for low values of rad and level=1==> quasi only level 0 is effective + float coefsd=0.85f;//arbitray value to reduce effect after sigma in all case + float coefmean=0.85f;//arbitray value to reduce effect after sigma in all case +// edge = 1.f + value * exp (expkoef);//estimate edge "pseudo variance" + //take into account local contrast + float refin= value * exp (expkoef); + if(cp.link==true && cp.noiseena){//combi + { + if(level==0) refin *= (1.f + cp.lev0s/50.f);// we can change this sensibility! + if(level==1) refin *= (1.f + cp.lev1s/50.f); + if(level==2) refin *= (1.f + cp.lev2s/50.f); + if(level==3) refin *= (1.f + cp.lev3s/50.f); + } + } + float edgePrecalc = 1.f + refin; //estimate edge "pseudo variance" + //bool exa=false; + if(cp.EDmet==2) {//curve + // if(exa) {//curve + float insigma=0.666f;//SD + float logmax=log(MaxP[level]);//log Max + float rapX=(mean[level]+sigma[level])/MaxP[level];//rapport between sD / max + float inx=log(insigma); + float iny=log(rapX); + float rap=inx/iny;//koef + float asig=0.166f/sigma[level]; + float bsig=0.5f-asig*mean[level]; + float amean=0.5f/mean[level]; + float absciss; + float kinterm; + float kmul; + // for (int i=0; i 10.f) edge=(aedstr*cp.eddet+bedstr)*(edgePrecalc*(1.f+koe[k]))/(1.f+0.9f*maxkoe); + else edge=(edgePrecalc*(1.f+koe[k]))/(1.f+0.9f*maxkoe); + } + if(lipschitz==true) { + if(level < 4) edge = 1.f +(edgePrecalc-1.f)*(koeLi[level*3][k])/(1.f+0.9f*maxkoeLi[level*3+ dir-1]); + else edge = edgePrecalc; + } + } + else edge = edgePrecalc; + + if(cp.edgcurv) { + if(fabs(WavCoeffs_L[dir][k])>= (mean[level]+sigma[level])){//for max + float valcour=log(fabs(WavCoeffs_L[dir][k])); + float valc=valcour-logmax; + float vald=valc*rap; + absciss=exp(vald); + + } + else if(fabs(WavCoeffs_L[dir][k])>=mean[level] && fabs(WavCoeffs_L[dir][k]) < (mean[level]+sigma[level])){ + absciss=asig*fabs(WavCoeffs_L[dir][k])+bsig; + } + else if(fabs(WavCoeffs_L[dir][k]) < mean[level]){ + absciss=amean*fabs(WavCoeffs_L[dir][k]); + } + // Threshold adjuster settings==> approximative for curve + //kmul about average cbrt(3--40 / 10)==>1.5 to 2.5 + //kmul about SD 10--60 / 35 ==> 2 + // kmul about low cbrt((5.f+cp.edg_low)/5.f);==> 1.5 + // kmul about max ==> 9 + // we can change these values + // result is different not best or bad than threshold slider...but similar + float abssd=4.f;//amplification reference + float bbssd=2.f;//mini ampli + float maxamp=2.5f;//maxi ampli at end + float maxampd=10.f;//maxi ampli at end + float a_abssd=(maxamp - abssd)/0.333f; + float b_abssd=maxamp-a_abssd; + float da_abssd=(maxampd - abssd)/0.333f; + float db_abssd=maxampd-da_abssd; + float am=(abssd-bbssd)/0.666f; + float kmuld=0.f; + if(absciss>0.666f && absciss < 1.f) {kmul=a_abssd*absciss + b_abssd;kmuld=da_abssd*absciss + db_abssd;}//about max ==> kinterm + else kmul = kmuld = absciss*am+bbssd; + kinterm=1.f; + float kc= kmul*(wavCLVCcurve[absciss*500.f]-0.5f); + float kcd= kmuld*(wavCLVCcurve[absciss*500.f]-0.5f); + float reduceeffect=0.6f; + if(kc >=0.f) + kinterm = 1.f + reduceeffect*kmul*(wavCLVCcurve[absciss*500.f]-0.5f);//about 1 to 3 general and big amplification for max (under 0) + else + kinterm = 1.f - (SQR(kcd))/10.f; + + if(kinterm<0.f) kinterm=0.01f; + edge *= kinterm; + if(edge < 1.f) + edge=1.f; + } + WavCoeffs_L[dir][k] *= edge; + } + } + } + else if(cp.EDmet==1) {//threshold adjuster + float MaxPCompare = MaxP[level]*SQR(cp.edg_max/100.f);//100 instead of b_r...case if b_r < 100 + float MaxNCompare = MaxN[level]*SQR(cp.edg_max/100.f);//always rduce a little edge for near max values + float edgeSdCompare = (mean[level]+1.5f*sigma[level])*SQR(cp.edg_sd/t_r);// 1.5 standard deviation #80% range between mean 50% and 80% + float edgeMeanCompare = mean[level]*SQR(cp.edg_mean/t_l); + float edgeLowCompare = (5.f+SQR(cp.edg_low)); + float edgeMeanFactor = cbrt(cp.edg_mean/t_l); + float interm; + if(cp.edg_low < 10.f) interm= cbrt((5.f+cp.edg_low)/5.f); + else interm=1.437f;//cbrt(3); + float edgeLowFactor = interm; + float edgeSdFactor = cp.edg_sd/t_r; + float edgeMaxFactor = SQR(cp.edg_max/b_r); + float edgMaxFsup=(cp.edg_max/b_r);//reduce increase of effect for high values contrast..if slider > b_r + + //for (int i=0; i 10.f) edge=(aedstr*cp.eddet+bedstr)*(edgePrecalc*(1.f+koe[k]))/(1.f+0.9f*maxkoe); + else edge=(edgePrecalc*(1.f+koe[k]))/(1.f+0.9f*maxkoe); + } + if(lipschitz==true) { + if(level < 4) edge = 1.f +(edgePrecalc-1.f)*(koeLi[level*3][k])/(1.f+0.9f*maxkoeLi[level*3+ dir-1]); + else edge = edgePrecalc; + } + } + else edge = edgePrecalc; + + //algorithm that take into account local contrast + // I use a thresholdadjuster with + // Bottom left ==> minimal low value for local contrast (not 0, but 5...we can change) + // 0 10*10 35*35 100*100 substantially correspond to the true distribution of low value, mean, standard-deviation and max (ed 5, 50, 400, 4000 + // Top left ==> mean reference value (for each level), we can change cbrt(cp.edg_mean/10.f) + // Top Right==> standard deviation (for each level) we can change (cp.edg_sd/35.f) + // bottom right ==> Max for positif and negatif contrast we can change cp.edg_max/100.f + // If we move sliders to the left, local contrast is reduced + // if we move sliders to the right local contrast is increased + // MaxP, MaxN, mean, sigma are calculated if necessary (val > 0) by evaluate2(), eval2(), aver() , sigma() + if(b_r < 100.f && cp.edg_max/b_r > 1.f) {//in case of b_r < 100 and slider move to right + if (WavCoeffs_L[dir][k] > MaxPCompare*cp.edg_max/b_r) { + edge *= edgMaxFsup; + if(edge < 1.f) + edge=1.f; + } + else if (WavCoeffs_L[dir][k] < MaxNCompare*cp.edg_max/b_r) { + edge *= edgMaxFsup; + if(edge < 1.f) + edge=1.f; + } + } + + if (WavCoeffs_L[dir][k] > MaxPCompare) { + edge *= edgeMaxFactor; + if(edge < 1.f) + edge=1.f; + }//reduce edge if > new max + else if (WavCoeffs_L[dir][k] < MaxNCompare) { + edge *= edgeMaxFactor; + if(edge < 1.f) + edge=1.f; + } + + if (fabs(WavCoeffs_L[dir][k]) >= edgeMeanCompare && fabs(WavCoeffs_L[dir][k]) < edgeSdCompare) { + //if (fabs(WavCoeffs_L[dir][i]) > edgeSdCompare) { + edge *= edgeSdFactor; + if(edge < 1.f) + edge=1.f; + }//mofify effect if sd change + if (fabs(WavCoeffs_L[dir][k]) < edgeMeanCompare) { + edge *= edgeMeanFactor; + if(edge < 1.f) + edge=1.f; + } // modify effect if mean change + if (fabs(WavCoeffs_L[dir][k]) < edgeLowCompare) { + edge *= edgeLowFactor; + if(edge < 1.f) + edge=1.f; + } + WavCoeffs_L[dir][k] *= edge; + } + } + } + if(lipschitz==false) { + delete [] koe; + } + } + + + if(cp.link==false && cp.noiseena) { //used both with denoise 1 2 3 + float refine=0.f; + for (int i=0; iwavelet.skinprotect; + const float skinprotneg = -skinprot; + const float factorHard = (1.f - skinprotneg/100.f); + + //to adjust increase contrast with local contrast + + //for each pixel and each level + float beta; + float mea[9]; + mea[0]=mean[level]/6.f; + mea[1]=mean[level]/2.f; + mea[2]=mean[level];// 50% data + mea[3]=mean[level] + sigma[level]/2.f; + mea[4]=mean[level] + sigma[level];//66% + mea[5]=mean[level] + 1.2f*sigma[level]; + mea[6]=mean[level] + 1.5f*sigma[level];// + mea[7]=mean[level] + 2.f*sigma[level];//95% + mea[8]=mean[level] + 2.5f*sigma[level];//99% + + bool skinControl = (skinprot != 0.f); + bool useChromAndHue = (skinprot != 0.f || cp.HSmet); + float modchro, kLlev; + + for (int i=0; iL[ii*2][jj*2]; + LL100=LL100init=LL/327.68f; + LL100res=WavCoeffs_L0[i]/327.68f; + float delta=fabs(LL100init-LL100res)/(maxlvl/2); + for(int ml=0;mlL[ii*2][jj*2]; + LL100=LL100init=LL/327.68f; + LL100res=WavCoeffs_L0[i]/327.68f; + float delta=fabs(LL100init-LL100res)/(maxlvl/2); + for(int ml=0;ml 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); //0 for skin and extand + } else if(skinprot < 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); + if (scale == 1.f) + scale=factorHard; + else + scale=1.f; + } + + } + if(Chutili){ + int i_i=i/W_L; + int j_j=i-i_i*W_L; + double lr; + float modhue2 = varhue[i_i][j_j]; + float valparam = float((ChCurve->getVal(lr=Color::huelab_to_huehsv2(modhue2))-0.5f));//get valparam=f(H) + + if(valparam > 0.f) scale2=1.f + 3.f* valparam;//arbitrary value + else scale2 = 1.f + 1.9f*valparam;//near 0 but not zero if curve # 0 + + //curve Contrast / hue + + } + // + //linear transition HL + float diagacc=1.f; + /* + if(cp.diag) { + if(dir <=2) diagacc=0.75f; + if(dir ==3) diagacc=1.5f; + } + */ + float alpha = (1024.f + 15.f *(float) cpMul*scale*scale2*beta*diagacc)/1024.f ; + if(cp.HSmet && cp.chromena){ + float aaal=(1.f-alpha)/((cp.b_lhl-cp.t_lhl)*kH[level]); + float bbal=1.f-aaal*cp.b_lhl*kH[level]; + float aaar=(alpha-1.f)/(cp.t_rhl-cp.b_rhl)*kH[level]; + float bbbr=1.f-cp.b_rhl*aaar*kH[level]; + //linear transition Shadows + float aaalS=(1.f-alpha)/(cp.b_lsl-cp.t_lsl); + float bbalS=1.f-aaalS*cp.b_lsl; + float aaarS=(alpha-1.f)/(cp.t_rsl-cp.b_rsl); + float bbbrS=1.f-cp.b_rsl*aaarS; + if(level <=cp.numlevH) {//in function of levels + if((LL100 > cp.t_lhl*kH[level] && LL100 < cp.t_rhl*kH[level])) {kLlev=alpha;} + else if((LL100 > cp.b_lhl*kH[level] && LL100 <= cp.t_lhl*kH[level])) kLlev=aaal*LL100+bbal; + else if((LL100 > cp.t_rhl*kH[level] && LL100 <= cp.b_rhl*kH[level])) kLlev=aaar*LL100+bbbr; + else kLlev=1.f; + } + if(level >=(9-cp.numlevS)) { + if((LL100 > cp.t_lsl && LL100 < cp.t_rsl)) kLlev=alpha; + else if((LL100 > cp.b_lsl && LL100 <= cp.t_lsl)) kLlev=aaalS*LL100+bbalS; + else if((LL100 > cp.t_rsl && LL100 <= cp.b_rsl)) kLlev=aaarS*LL100+bbbrS; + else kLlev=1.f; + } + + } + else kLlev=alpha; + + WavCoeffs_L[dir][i]*=(kLlev); + } + } +if(waOpacityCurveW) cp.opaW=true; + +if(cp.bam && cp.finena) { +if(cp.opaW && cp.BAmet==2){ + int iteration = cp.ite; + int itplus=7+iteration; + int itmoins= 7-iteration; + int med = maxlvl/2; + int it; + if(level < med) {it=itmoins; } + else if(level == med) it=7; + else if(level > med) it=itplus; + + for(int j=0; j < it; j++) { + //float bal = cp.balan;//-100 +100 + float kba=1.f; + float k1; + float k2; + // if(dir <3) kba= 1.f + bal/600.f; + // if(dir==3) kba = 1.f - bal/300.f; + for (int i=0; iL[ii*2][jj*2]/327.68f; + k1=600.f; + k2=300.f; + k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16 + k2=k1*2.f; + if(dir <3) kba= 1.f + k1; + if(dir==3) kba = 1.f - k2; + + WavCoeffs_L[dir][i] *=(kba); + } + } +} +if(cp.BAmet==1){ + int iteration = cp.ite; + int itplus=7+iteration; + int itmoins= 7-iteration; + int med = maxlvl/2; + int it; + if(level < med) {it=itmoins; } + else if(level == med) it=7; + else if(level > med) it=itplus; + + for(int j=0; j < it; j++) { + float bal = cp.balan;//-100 +100 + float kba=1.f; + float k1; + float k2; + // if(dir <3) kba= 1.f + bal/600.f; + // if(dir==3) kba = 1.f - bal/300.f; + for (int i=0; iL[ii*2][jj*2]/327.68f; + float aa=4970.f; + float bb=-397000.f; + float b0=100000.f; + float a0=-4970.f; + if(LL100> 80.f) {k1=aa*LL100 + bb;k2=0.5f*k1;} + if(LL100< 20.f) {k1=a0*LL100 + b0;k2=0.5f*k1;} + //k1=600.f; + //k2=300.f; + //k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16 + //k2=k1*2.f; + if(dir <3) kba= 1.f + bal/k1; + if(dir==3) kba = 1.f - bal/k2; + + WavCoeffs_L[dir][i] *=(kba); + } + } +} + +} + + // to see each level of wavelet ...level from 0 to 8 + int choicelevel = atoi(params->wavelet.Lmethod.data())-1; + choicelevel = choicelevel == -1 ? 4 : choicelevel; + } + + void ImProcFunctions::ContAllAB (LabImage * labco, int maxlvl, float ** varhue, float **varchrom, float ** WavCoeffs_ab, float * WavCoeffs_ab0, int level, int dir, const WavOpacityCurveW & waOpacityCurveW, struct cont_params &cp, + int W_ab, int H_ab, const bool useChannelA) + { + float cpMul = cp.mul[level]; + if(cpMul != 0.f && cp.CHmet==2 && cp.chro != 0.f && cp.chromena) { // cpMul == 0.f or cp.chro = 0.f means all will be multiplied by 1.f, so we can skip this + const float skinprot = params->wavelet.skinprotect; + const float skinprotneg = -skinprot; + const float factorHard = (1.f - skinprotneg/100.f); + const float cpChrom = cp.chro; + + //to adjust increase contrast with local contrast + bool useSkinControl = (skinprot != 0.f); + float alphaC =(1024.f + 15.f *cpMul*cpChrom/50.f)/1024.f ; + for (int i=0; iL[ii*2][jj*2]/327.68f; + float modhue = varhue[ii][jj]; + float modchro = varchrom[ii*2][jj*2]; + // hue chroma skin with initial lab datas + float scale=1.f; + if(skinprot > 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); //0 for skin and extand + } else if(skinprot < 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); + scale = (scale == 1.f) ? factorHard : 1.f; + } + alphaC =(1024.f + 15.f *cpMul*cpChrom*scale/50.f)/1024.f ; + } + WavCoeffs_ab[dir][i] *= alphaC; + } + } + //Curve chro + + float cpMulC = cp.mulC[level]; + // if( (cp.curv || cp.CHSLmet==1) && cp.CHmet!=2 && level < 9 && cpMulC != 0.f) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip + if( cp.CHmet!=2 && level < 9 && cpMulC != 0.f && cp.chromena) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip + float modchro, modhue, kClev; + const float skinprot = params->wavelet.skinprotect; + const float skinprotneg = -skinprot; + const float factorHard = (1.f - skinprotneg/100.f); + bool useSkinControl = (skinprot != 0.f); + + for (int i=0; iL[ii*2][jj*2]; + float LL100=LL/327.68f; + float scale=1.f; + modchro = varchrom[ii*2][jj*2]; + + if(useSkinControl) { + // hue chroma skin with initial lab datas + modhue = varhue[ii][jj]; + scale=1.f; + if(skinprot > 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 1); //1 for curve + } + else if(skinprot < 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 1); + scale = (scale == 1.f) ? factorHard : 1.f; + } + } + float beta = (1024.f + 20.f * cpMulC * scale)/1024.f ; + if(beta < 0.02f) + beta=0.02f; + kClev = beta; + if(cp.CHmet==1){ + if(level < cp.chrom) { + //linear for saturated + if((modchro > cp.t_lsat && modchro < cp.t_rsat)) + kClev=beta; + else if((modchro > cp.b_lsat && modchro <= cp.t_lsat)) { + float aaal=(1.f-beta)/(cp.b_lsat-cp.t_lsat); + float bbal=1.f-aaal*cp.b_lsat; + kClev=aaal*modchro+bbal; + } else if((modchro > cp.t_rsat && modchro <= cp.b_rsat)) { + float aaar=(beta-1.f)/(cp.t_rsat-cp.b_rsat); + float bbbr=1.f-cp.b_rsat*aaar; + kClev=aaar*modchro+bbbr; + } else + kClev=1.f; + } else { + //linear for pastel + if((modchro > cp.t_lpast && modchro < cp.t_rpast)) + kClev=beta; + else if((modchro > cp.b_lpast && modchro <= cp.t_lpast)) { + float aaalS=(1.f-beta)/(cp.b_lpast-cp.t_lpast); + float bbalS=1.f-aaalS*cp.b_lpast; + kClev=aaalS*modchro+bbalS; + } else if((modchro > cp.t_rpast && modchro <= cp.b_rpast)) { + float aaarS=(beta-1.f)/(cp.t_rpast-cp.b_rpast); + float bbbrS=1.f-cp.b_rpast*aaarS; + kClev=aaarS*modchro+bbbrS; + } else + kClev=1.f; + } + } + else if(cp.CHmet==0) + kClev=beta; + WavCoeffs_ab[dir][i] *= kClev; + } + } + + bool useOpacity; + float mulOpacity; + if(useChannelA) { + useOpacity = cp.opaRG; + mulOpacity = cp.mulopaRG[level]; + } + else { + useOpacity = cp.opaBY; + mulOpacity = cp.mulopaBY[level]; + } + + if((useOpacity && level < 9 && mulOpacity != 0.f) && cp.toningena) { //toning + + float beta = (1024.f + 20.f * mulOpacity)/1024.f ; + //float beta = (1000.f * mulOpacity); + for (int i=0; i med) it=itplus; + + for(int j=0; j < it; j++) { + //float bal = cp.balan;//-100 +100 + float kba=1.f; + float k1; + float k2; + // if(dir <3) kba= 1.f + bal/600.f; + // if(dir==3) kba = 1.f - bal/300.f; + for (int i=0; iL[ii*2][jj*2]/327.68f; + k1=600.f; + k2=300.f; + k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16 + k2=k1*2.f; + if(dir <3) kba= 1.f + k1; + if(dir==3) kba = 1.f - k2; + + WavCoeffs_ab[dir][i] *=(kba); + } + } +} +if(cp.BAmet==1){ + int iteration = cp.ite; + int itplus=7+iteration; + int itmoins= 7-iteration; + int med = maxlvl/2; + int it; + if(level < med) {it=itmoins; } + else if(level == med) it=7; + else if(level > med) it=itplus; + + for(int j=0; j < it; j++) { + float bal = cp.balan;//-100 +100 + float kba=1.f; + float k1; + float k2; + // if(dir <3) kba= 1.f + bal/600.f; + // if(dir==3) kba = 1.f - bal/300.f; + for (int i=0; iL[ii*2][jj*2]/327.68f; + float aa=4970.f; + float bb=-397000.f; + float b0=100000.f; + float a0=-4970.f; + if(LL100> 80.f) {k1=aa*LL100 + bb;k2=0.5f*k1;} + if(LL100< 20.f) {k1=a0*LL100 + b0;k2=0.5f*k1;} + //k1=600.f; + //k2=300.f; + //k1=0.3f*(waOpacityCurveW[6.f*LL100]-0.5f);//k1 between 0 and 0.5 0.5==> 1/6=0.16 + //k2=k1*2.f; + if(dir <3) kba= 1.f + bal/k1; + if(dir==3) kba = 1.f - bal/k2; + + WavCoeffs_ab[dir][i] *=(kba); + } + } +} + +} + + // to see each level of wavelet ...level from 0 to 8 + int choicelevel = atoi(params->wavelet.Lmethod.data())-1; + choicelevel = choicelevel == -1 ? 4 : choicelevel; + int choiceClevel=0; + if(params->wavelet.CLmethod=="one") choiceClevel=0; + else if(params->wavelet.CLmethod=="inf") choiceClevel=1; + else if(params->wavelet.CLmethod=="sup") choiceClevel=2; + else if(params->wavelet.CLmethod=="all") choiceClevel=3; + int choiceDir=0; + if(params->wavelet.Dirmethod=="one") choiceDir=1; + else if(params->wavelet.Dirmethod=="two") choiceDir=2; + else if(params->wavelet.Dirmethod=="thr") choiceDir=3; + else if(params->wavelet.Dirmethod=="all") choiceDir=0; + + int dir1 = (choiceDir == 2) ? 1 : 2; + int dir2 = (choiceDir == 3) ? 1 : 3; + if(choiceClevel<3) { // not all levels visible, paint residual + if(level == 0) { + if(cp.backm!=2) { // nothing to change when residual is used as background + float backGroundChroma = (cp.backm==1) ? 0.f : 0.f;//we can change first to colorized... + for (int i=0; i= cp.maxilev) { + for (int dir=1; dir<4; dir++) { + for (int i=0; i choicelevel) { + for (int dir=1; dir<4; dir++) { + for (int i=0; i= choicelevel + if(level > choicelevel) { + for (int i=0; i= choicelevel + if(choicelevel >= cp.maxilev) { + for (int dir=1; dir<4; dir++) { + for (int i=0; i // printf - -extern "C" { - void RunExample1(); - void RunExample2(); - void RunExample3(); - void RunExample4(); - void RunExample5(); -} - -int main(int argc, char* argv[]) -{ - // select which example to run here - const int which = 1; - - // run the appropriate example - switch (which) { - case 1: RunExample1(); break; - case 2: RunExample2(); break; - case 3: RunExample3(); break; - case 4: RunExample4(); break; // Note: example4 reads output from example 3 - case 5: RunExample5(); break; - default: printf("There is no example number %d\n", which); - } - return 0; -} - +// main.cpp : Defines the entry point for the console application. +// + +#include // printf + +extern "C" { + void RunExample1(); + void RunExample2(); + void RunExample3(); + void RunExample4(); + void RunExample5(); +} + +int main(int argc, char* argv[]) +{ + // select which example to run here + const int which = 1; + + // run the appropriate example + switch (which) { + case 1: RunExample1(); break; + case 2: RunExample2(); break; + case 3: RunExample3(); break; + case 4: RunExample4(); break; // Note: example4 reads output from example 3 + case 5: RunExample5(); break; + default: printf("There is no example number %d\n", which); + } + return 0; +} + diff --git a/rtengine/klt/speed.txt b/rtengine/klt/speed.txt index 08e20e59e..08a7351ca 100644 --- a/rtengine/klt/speed.txt +++ b/rtengine/klt/speed.txt @@ -1,12 +1,12 @@ -======================================================================= -speed of KLT versus OpenCV feature tracker on a 2.8 GHz P4 computer: - - KLT OpenCV ---------------------------------------------- -track (100) 54 ms 47 ms -track/replace (100) 95 ms 82 ms -track (1000) 79 ms 59 ms -track/replace (1000) 139 ms 103 ms - -The number of features is given in parentheses. These times were computed by running the code on the same image multiple times in succession, then averaging. As a result, they may not reflect the overhead of loading the image and cache misses that would occur in a real scenario. -======================================================================= +======================================================================= +speed of KLT versus OpenCV feature tracker on a 2.8 GHz P4 computer: + + KLT OpenCV +--------------------------------------------- +track (100) 54 ms 47 ms +track/replace (100) 95 ms 82 ms +track (1000) 79 ms 59 ms +track/replace (1000) 139 ms 103 ms + +The number of features is given in parentheses. These times were computed by running the code on the same image multiple times in succession, then averaging. As a result, they may not reflect the overhead of loading the image and cache misses that would occur in a real scenario. +======================================================================= diff --git a/rtengine/klt/trackFeatures.cc b/rtengine/klt/trackFeatures.cc index 2b6b81f5f..3ade7264f 100644 --- a/rtengine/klt/trackFeatures.cc +++ b/rtengine/klt/trackFeatures.cc @@ -1,1542 +1,1542 @@ -/********************************************************************* - * trackFeatures.c - * - *********************************************************************/ - -/* Standard includes */ -#include -#include /* fabs() */ -#include /* malloc() */ -#include /* fflush() */ - -/* Our includes */ -#include "base.h" -#include "error.h" -#include "convolve.h" /* for computing pyramid */ -#include "klt.h" -#include "klt_util.h" /* _KLT_FloatImage */ -#include "pyramid.h" /* _KLT_Pyramid */ - -extern int KLT_verbose; - -typedef float *_FloatWindow; - -/********************************************************************* - * _interpolate - * - * Given a point (x,y) in an image, computes the bilinear interpolated - * gray-level value of the point in the image. - */ - -static float _interpolate( - float x, - float y, - _KLT_FloatImage img) -{ - int xt = (int) x; /* coordinates of top-left corner */ - int yt = (int) y; - float ax = x - xt; - float ay = y - yt; - float *ptr = img->data + (img->ncols*yt) + xt; - -#ifndef _DNDEBUG - if (xt<0 || yt<0 || xt>=img->ncols-1 || yt>=img->nrows-1) { - fprintf(stderr, "(xt,yt)=(%d,%d) imgsize=(%d,%d)\n" - "(x,y)=(%f,%f) (ax,ay)=(%f,%f)\n", - xt, yt, img->ncols, img->nrows, x, y, ax, ay); - fflush(stderr); - } -#endif - - assert (xt >= 0 && yt >= 0 && xt <= img->ncols - 2 && yt <= img->nrows - 2); - - return ( (1-ax) * (1-ay) * *ptr + - ax * (1-ay) * *(ptr+1) + - (1-ax) * ay * *(ptr+(img->ncols)) + - ax * ay * *(ptr+(img->ncols)+1) ); -} - - -/********************************************************************* - * _computeIntensityDifference - * - * Given two images and the window center in both images, - * aligns the images wrt the window and computes the difference - * between the two overlaid images. - */ - -static void _computeIntensityDifference( - _KLT_FloatImage img1, /* images */ - _KLT_FloatImage img2, - float x1, float y1, /* center of window in 1st img */ - float x2, float y2, /* center of window in 2nd img */ - int width, int height, /* size of window */ - _FloatWindow imgdiff) /* output */ -{ - int hw = width/2, hh = height/2; - float g1, g2; - int i, j; - - /* Compute values */ - for (j = -hh ; j <= hh ; j++) - for (i = -hw ; i <= hw ; i++) { - g1 = _interpolate(x1+i, y1+j, img1); - g2 = _interpolate(x2+i, y2+j, img2); - *imgdiff++ = g1 - g2; - } -} - - -/********************************************************************* - * _computeGradientSum - * - * Given two gradients and the window center in both images, - * aligns the gradients wrt the window and computes the sum of the two - * overlaid gradients. - */ - -static void _computeGradientSum( - _KLT_FloatImage gradx1, /* gradient images */ - _KLT_FloatImage grady1, - _KLT_FloatImage gradx2, - _KLT_FloatImage grady2, - float x1, float y1, /* center of window in 1st img */ - float x2, float y2, /* center of window in 2nd img */ - int width, int height, /* size of window */ - _FloatWindow gradx, /* output */ - _FloatWindow grady) /* " */ -{ - int hw = width/2, hh = height/2; - float g1, g2; - int i, j; - - /* Compute values */ - for (j = -hh ; j <= hh ; j++) - for (i = -hw ; i <= hw ; i++) { - g1 = _interpolate(x1+i, y1+j, gradx1); - g2 = _interpolate(x2+i, y2+j, gradx2); - *gradx++ = g1 + g2; - g1 = _interpolate(x1+i, y1+j, grady1); - g2 = _interpolate(x2+i, y2+j, grady2); - *grady++ = g1 + g2; - } -} - -/********************************************************************* - * _computeIntensityDifferenceLightingInsensitive - * - * Given two images and the window center in both images, - * aligns the images wrt the window and computes the difference - * between the two overlaid images; normalizes for overall gain and bias. - */ - -static void _computeIntensityDifferenceLightingInsensitive( - _KLT_FloatImage img1, /* images */ - _KLT_FloatImage img2, - float x1, float y1, /* center of window in 1st img */ - float x2, float y2, /* center of window in 2nd img */ - int width, int height, /* size of window */ - _FloatWindow imgdiff) /* output */ -{ - int hw = width/2, hh = height/2; - float g1, g2, sum1_squared = 0, sum2_squared = 0; - int i, j; - - float sum1 = 0, sum2 = 0; - float mean1, mean2,alpha,belta; - /* Compute values */ - for (j = -hh ; j <= hh ; j++) - for (i = -hw ; i <= hw ; i++) { - g1 = _interpolate(x1+i, y1+j, img1); - g2 = _interpolate(x2+i, y2+j, img2); - sum1 += g1; sum2 += g2; - sum1_squared += g1*g1; - sum2_squared += g2*g2; - } - mean1=sum1_squared/(width*height); - mean2=sum2_squared/(width*height); - alpha = (float) sqrt(mean1/mean2); - mean1=sum1/(width*height); - mean2=sum2/(width*height); - belta = mean1-alpha*mean2; - - for (j = -hh ; j <= hh ; j++) - for (i = -hw ; i <= hw ; i++) { - g1 = _interpolate(x1+i, y1+j, img1); - g2 = _interpolate(x2+i, y2+j, img2); - *imgdiff++ = g1- g2*alpha-belta; - } -} - - -/********************************************************************* - * _computeGradientSumLightingInsensitive - * - * Given two gradients and the window center in both images, - * aligns the gradients wrt the window and computes the sum of the two - * overlaid gradients; normalizes for overall gain and bias. - */ - -static void _computeGradientSumLightingInsensitive( - _KLT_FloatImage gradx1, /* gradient images */ - _KLT_FloatImage grady1, - _KLT_FloatImage gradx2, - _KLT_FloatImage grady2, - _KLT_FloatImage img1, /* images */ - _KLT_FloatImage img2, - - float x1, float y1, /* center of window in 1st img */ - float x2, float y2, /* center of window in 2nd img */ - int width, int height, /* size of window */ - _FloatWindow gradx, /* output */ - _FloatWindow grady) /* " */ -{ - int hw = width/2, hh = height/2; - float g1, g2, sum1_squared = 0, sum2_squared = 0; - int i, j; - - float mean1, mean2, alpha; - for (j = -hh ; j <= hh ; j++) - for (i = -hw ; i <= hw ; i++) { - g1 = _interpolate(x1+i, y1+j, img1); - g2 = _interpolate(x2+i, y2+j, img2); - sum1_squared += g1; sum2_squared += g2; - } - mean1 = sum1_squared/(width*height); - mean2 = sum2_squared/(width*height); - alpha = (float) sqrt(mean1/mean2); - - /* Compute values */ - for (j = -hh ; j <= hh ; j++) - for (i = -hw ; i <= hw ; i++) { - g1 = _interpolate(x1+i, y1+j, gradx1); - g2 = _interpolate(x2+i, y2+j, gradx2); - *gradx++ = g1 + g2*alpha; - g1 = _interpolate(x1+i, y1+j, grady1); - g2 = _interpolate(x2+i, y2+j, grady2); - *grady++ = g1+ g2*alpha; - } -} - -/********************************************************************* - * _compute2by2GradientMatrix - * - */ - -static void _compute2by2GradientMatrix( - _FloatWindow gradx, - _FloatWindow grady, - int width, /* size of window */ - int height, - float *gxx, /* return values */ - float *gxy, - float *gyy) - -{ - float gx, gy; - int i; - - /* Compute values */ - *gxx = 0.0; *gxy = 0.0; *gyy = 0.0; - for (i = 0 ; i < width * height ; i++) { - gx = *gradx++; - gy = *grady++; - *gxx += gx*gx; - *gxy += gx*gy; - *gyy += gy*gy; - } -} - - -/********************************************************************* - * _compute2by1ErrorVector - * - */ - -static void _compute2by1ErrorVector( - _FloatWindow imgdiff, - _FloatWindow gradx, - _FloatWindow grady, - int width, /* size of window */ - int height, - float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */ - float *ex, /* return values */ - float *ey) -{ - float diff; - int i; - - /* Compute values */ - *ex = 0; *ey = 0; - for (i = 0 ; i < width * height ; i++) { - diff = *imgdiff++; - *ex += diff * (*gradx++); - *ey += diff * (*grady++); - } - *ex *= step_factor; - *ey *= step_factor; -} - - -/********************************************************************* - * _solveEquation - * - * Solves the 2x2 matrix equation - * [gxx gxy] [dx] = [ex] - * [gxy gyy] [dy] = [ey] - * for dx and dy. - * - * Returns KLT_TRACKED on success and KLT_SMALL_DET on failure - */ - -static int _solveEquation( - float gxx, float gxy, float gyy, - float ex, float ey, - float small, - float *dx, float *dy) -{ - float det = gxx*gyy - gxy*gxy; - - - if (det < small) return KLT_SMALL_DET; - - *dx = (gyy*ex - gxy*ey)/det; - *dy = (gxx*ey - gxy*ex)/det; - return KLT_TRACKED; -} - - -/********************************************************************* - * _allocateFloatWindow - */ - -static _FloatWindow _allocateFloatWindow( - int width, - int height) -{ - _FloatWindow fw; - - fw = (_FloatWindow) malloc(width*height*sizeof(float)); - if (fw == NULL) { - KLTError("(_allocateFloatWindow) Out of memory."); - exit(1); - } - return fw; -} - - -/********************************************************************* - * _printFloatWindow - * (for debugging purposes) - */ - -/* -static void _printFloatWindow( - _FloatWindow fw, - int width, - int height) -{ - int i, j; - - fprintf(stderr, "\n"); - for (i = 0 ; i < width ; i++) { - for (j = 0 ; j < height ; j++) { - fprintf(stderr, "%6.1f ", *fw++); - } - fprintf(stderr, "\n"); - } -} -*/ - - -/********************************************************************* - * _sumAbsFloatWindow - */ - -static float _sumAbsFloatWindow( - _FloatWindow fw, - int width, - int height) -{ - float sum = 0.0; - int w; - - for ( ; height > 0 ; height--) - for (w=0 ; w < width ; w++) - sum += (float) fabs(*fw++); - - return sum; -} - - -/********************************************************************* - * _trackFeature - * - * Tracks a feature point from one image to the next. - * - * RETURNS - * KLT_SMALL_DET if feature is lost, - * KLT_MAX_ITERATIONS if tracking stopped because iterations timed out, - * KLT_TRACKED otherwise. - */ - -static int _trackFeature( - float x1, /* location of window in first image */ - float y1, - float *x2, /* starting location of search in second image */ - float *y2, - _KLT_FloatImage img1, - _KLT_FloatImage gradx1, - _KLT_FloatImage grady1, - _KLT_FloatImage img2, - _KLT_FloatImage gradx2, - _KLT_FloatImage grady2, - int width, /* size of window */ - int height, - float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */ - int max_iterations, - float small, /* determinant threshold for declaring KLT_SMALL_DET */ - float th, /* displacement threshold for stopping */ - float max_residue, /* residue threshold for declaring KLT_LARGE_RESIDUE */ - int lighting_insensitive) /* whether to normalize for gain and bias */ -{ - _FloatWindow imgdiff, gradx, grady; - float gxx, gxy, gyy, ex, ey, dx, dy; - int iteration = 0; - int status; - int hw = width/2; - int hh = height/2; - int nc = img1->ncols; - int nr = img1->nrows; - float one_plus_eps = 1.001f; /* To prevent rounding errors */ - - - /* Allocate memory for windows */ - imgdiff = _allocateFloatWindow(width, height); - gradx = _allocateFloatWindow(width, height); - grady = _allocateFloatWindow(width, height); - - /* Iteratively update the window position */ - do { - - /* If out of bounds, exit loop */ - if ( x1-hw < 0.0f || nc-( x1+hw) < one_plus_eps || - *x2-hw < 0.0f || nc-(*x2+hw) < one_plus_eps || - y1-hh < 0.0f || nr-( y1+hh) < one_plus_eps || - *y2-hh < 0.0f || nr-(*y2+hh) < one_plus_eps) { - status = KLT_OOB; - break; - } - - /* Compute gradient and difference windows */ - if (lighting_insensitive) { - _computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, *x2, *y2, - width, height, imgdiff); - _computeGradientSumLightingInsensitive(gradx1, grady1, gradx2, grady2, - img1, img2, x1, y1, *x2, *y2, width, height, gradx, grady); - } else { - _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2, - width, height, imgdiff); - _computeGradientSum(gradx1, grady1, gradx2, grady2, - x1, y1, *x2, *y2, width, height, gradx, grady); - } - - - /* Use these windows to construct matrices */ - _compute2by2GradientMatrix(gradx, grady, width, height, - &gxx, &gxy, &gyy); - _compute2by1ErrorVector(imgdiff, gradx, grady, width, height, step_factor, - &ex, &ey); - - /* Using matrices, solve equation for new displacement */ - status = _solveEquation(gxx, gxy, gyy, ex, ey, small, &dx, &dy); - if (status == KLT_SMALL_DET) break; - - *x2 += dx; - *y2 += dy; - iteration++; - - } while ((fabs(dx)>=th || fabs(dy)>=th) && iteration < max_iterations); - - /* Check whether window is out of bounds */ - if (*x2-hw < 0.0f || nc-(*x2+hw) < one_plus_eps || - *y2-hh < 0.0f || nr-(*y2+hh) < one_plus_eps) - status = KLT_OOB; - - /* Check whether residue is too large */ - if (status == KLT_TRACKED) { - if (lighting_insensitive) - _computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, *x2, *y2, - width, height, imgdiff); - else - _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2, - width, height, imgdiff); - if (_sumAbsFloatWindow(imgdiff, width, height)/(width*height) > max_residue) - status = KLT_LARGE_RESIDUE; - } - - /* Free memory */ - free(imgdiff); free(gradx); free(grady); - - /* Return appropriate value */ - if (status == KLT_SMALL_DET) return KLT_SMALL_DET; - else if (status == KLT_OOB) return KLT_OOB; - else if (status == KLT_LARGE_RESIDUE) return KLT_LARGE_RESIDUE; - else if (iteration >= max_iterations) return KLT_MAX_ITERATIONS; - else return KLT_TRACKED; - -} - - -/*********************************************************************/ - -static KLT_BOOL _outOfBounds( - float x, - float y, - int ncols, - int nrows, - int borderx, - int bordery) -{ - return (x < borderx || x > ncols-1-borderx || - y < bordery || y > nrows-1-bordery ); -} - - - - -/********************************************************************** -* CONSISTENCY CHECK OF FEATURES BY AFFINE MAPPING (BEGIN) -* -* Created by: Thorsten Thormaehlen (University of Hannover) June 2004 -* thormae@tnt.uni-hannover.de -* -* Permission is granted to any individual or institution to use, copy, modify, -* and distribute this part of the software, provided that this complete authorship -* and permission notice is maintained, intact, in all copies. -* -* This software is provided "as is" without express or implied warranty. -* -* -* The following static functions are helpers for the affine mapping. -* They all start with "_am". -* There are also small changes in other files for the -* affine mapping these are all marked by "for affine mapping" -* -* Thanks to Kevin Koeser (koeser@mip.informatik.uni-kiel.de) for fixing a bug -*/ - -#define SWAP_ME(X,Y) {temp=(X);(X)=(Y);(Y)=temp;} - -static float **_am_matrix(long nr, long nc) -{ - float **m; - int a; - m = (float **) malloc((size_t)(nr*sizeof(float*))); - m[0] = (float *) malloc((size_t)((nr*nc)*sizeof(float))); - for(a = 1; a < nr; a++) m[a] = m[a-1]+nc; - return m; -} - -static void _am_free_matrix(float **m) -{ - free(m[0]); - free(m); -} - - -static int _am_gauss_jordan_elimination(float **a, int n, float **b, int m) -{ - /* re-implemented from Numerical Recipes in C */ - int *indxc,*indxr,*ipiv; - int i,j,k,l,ll; - float big,dum,pivinv,temp; - int col = 0; - int row = 0; - - indxc=(int *)malloc((size_t) (n*sizeof(int))); - indxr=(int *)malloc((size_t) (n*sizeof(int))); - ipiv=(int *)malloc((size_t) (n*sizeof(int))); - for (j=0;j= big) { - big= (float) fabs(a[j][k]); - row=j; - col=k; - } - } else if (ipiv[k] > 1) { - free(ipiv); free(indxr); free(indxc); return KLT_SMALL_DET; - } - } - ++(ipiv[col]); - if (row != col) { - for (l=0;l=0;l--) { - if (indxr[l] != indxc[l]) - for (k=0;kncols/2, hh = window->nrows/2; - int x0 = (int) x; - int y0 = (int) y; - float * windata = window->data; - int offset; - int i, j; - - assert(x0 - hw >= 0); - assert(y0 - hh >= 0); - assert(x0 + hw <= img->ncols); - assert(y0 + hh <= img->nrows); - - /* copy values */ - for (j = -hh ; j <= hh ; j++) - for (i = -hw ; i <= hw ; i++) { - offset = (j+y0)*img->ncols + (i+x0); - *windata++ = *(img->data+offset); - } -} - -/********************************************************************* - * _am_computeIntensityDifferenceAffine - * - * Given two images and the window center in both images, - * aligns the images with the window and computes the difference - * between the two overlaid images using the affine mapping. - * A = [ Axx Axy] - * [ Ayx Ayy] -*/ - -static void _am_computeIntensityDifferenceAffine( - _KLT_FloatImage img1, /* images */ - _KLT_FloatImage img2, - float x1, float y1, /* center of window in 1st img */ - float x2, float y2, /* center of window in 2nd img */ - float Axx, float Ayx , float Axy, float Ayy, /* affine mapping */ - int width, int height, /* size of window */ - _FloatWindow imgdiff) /* output */ -{ - int hw = width/2, hh = height/2; - float g1, g2; - int i, j; - float mi, mj; - - /* Compute values */ - for (j = -hh ; j <= hh ; j++) - for (i = -hw ; i <= hw ; i++) { - g1 = _interpolate(x1+i, y1+j, img1); - mi = Axx * i + Axy * j; - mj = Ayx * i + Ayy * j; - g2 = _interpolate(x2+mi, y2+mj, img2); - *imgdiff++ = g1 - g2; - } -} - -/********************************************************************* - * _am_compute6by6GradientMatrix - * - */ - -static void _am_compute6by6GradientMatrix( - _FloatWindow gradx, - _FloatWindow grady, - int width, /* size of window */ - int height, - float **T) /* return values */ -{ - int hw = width/2, hh = height/2; - int i, j; - float gx, gy, gxx, gxy, gyy, x, y, xx, xy, yy; - - - /* Set values to zero */ - for (j = 0 ; j < 6 ; j++) { - for (i = j ; i < 6 ; i++) { - T[j][i] = 0.0; - } - } - - for (j = -hh ; j <= hh ; j++) { - for (i = -hw ; i <= hw ; i++) { - gx = *gradx++; - gy = *grady++; - gxx = gx * gx; - gxy = gx * gy; - gyy = gy * gy; - x = (float) i; - y = (float) j; - xx = x * x; - xy = x * y; - yy = y * y; - - T[0][0] += xx * gxx; - T[0][1] += xx * gxy; - T[0][2] += xy * gxx; - T[0][3] += xy * gxy; - T[0][4] += x * gxx; - T[0][5] += x * gxy; - - T[1][1] += xx * gyy; - T[1][2] += xy * gxy; - T[1][3] += xy * gyy; - T[1][4] += x * gxy; - T[1][5] += x * gyy; - - T[2][2] += yy * gxx; - T[2][3] += yy * gxy; - T[2][4] += y * gxx; - T[2][5] += y * gxy; - - T[3][3] += yy * gyy; - T[3][4] += y * gxy; - T[3][5] += y * gyy; - - T[4][4] += gxx; - T[4][5] += gxy; - - T[5][5] += gyy; - } - } - - for (j = 0 ; j < 5 ; j++) { - for (i = j+1 ; i < 6 ; i++) { - T[i][j] = T[j][i]; - } - } - -} - - - -/********************************************************************* - * _am_compute6by1ErrorVector - * - */ - -static void _am_compute6by1ErrorVector( - _FloatWindow imgdiff, - _FloatWindow gradx, - _FloatWindow grady, - int width, /* size of window */ - int height, - float **e) /* return values */ -{ - int hw = width/2, hh = height/2; - int i, j; - float diff, diffgradx, diffgrady; - - /* Set values to zero */ - for(i = 0; i < 6; i++) e[i][0] = 0.0; - - /* Compute values */ - for (j = -hh ; j <= hh ; j++) { - for (i = -hw ; i <= hw ; i++) { - diff = *imgdiff++; - diffgradx = diff * (*gradx++); - diffgrady = diff * (*grady++); - e[0][0] += diffgradx * i; - e[1][0] += diffgrady * i; - e[2][0] += diffgradx * j; - e[3][0] += diffgrady * j; - e[4][0] += diffgradx; - e[5][0] += diffgrady; - } - } - - for(i = 0; i < 6; i++) e[i][0] *= 0.5; - -} - - -/********************************************************************* - * _am_compute4by4GradientMatrix - * - */ - -static void _am_compute4by4GradientMatrix( - _FloatWindow gradx, - _FloatWindow grady, - int width, /* size of window */ - int height, - float **T) /* return values */ -{ - int hw = width/2, hh = height/2; - int i, j; - float gx, gy, x, y; - - - /* Set values to zero */ - for (j = 0 ; j < 4 ; j++) { - for (i = 0 ; i < 4 ; i++) { - T[j][i] = 0.0; - } - } - - for (j = -hh ; j <= hh ; j++) { - for (i = -hw ; i <= hw ; i++) { - gx = *gradx++; - gy = *grady++; - x = (float) i; - y = (float) j; - T[0][0] += (x*gx+y*gy) * (x*gx+y*gy); - T[0][1] += (x*gx+y*gy)*(x*gy-y*gx); - T[0][2] += (x*gx+y*gy)*gx; - T[0][3] += (x*gx+y*gy)*gy; - - T[1][1] += (x*gy-y*gx) * (x*gy-y*gx); - T[1][2] += (x*gy-y*gx)*gx; - T[1][3] += (x*gy-y*gx)*gy; - - T[2][2] += gx*gx; - T[2][3] += gx*gy; - - T[3][3] += gy*gy; - } - } - - for (j = 0 ; j < 3 ; j++) { - for (i = j+1 ; i < 4 ; i++) { - T[i][j] = T[j][i]; - } - } - -} - -/********************************************************************* - * _am_compute4by1ErrorVector - * - */ - -static void _am_compute4by1ErrorVector( - _FloatWindow imgdiff, - _FloatWindow gradx, - _FloatWindow grady, - int width, /* size of window */ - int height, - float **e) /* return values */ -{ - int hw = width/2, hh = height/2; - int i, j; - float diff, diffgradx, diffgrady; - - /* Set values to zero */ - for(i = 0; i < 4; i++) e[i][0] = 0.0; - - /* Compute values */ - for (j = -hh ; j <= hh ; j++) { - for (i = -hw ; i <= hw ; i++) { - diff = *imgdiff++; - diffgradx = diff * (*gradx++); - diffgrady = diff * (*grady++); - e[0][0] += diffgradx * i + diffgrady * j; - e[1][0] += diffgrady * i - diffgradx * j; - e[2][0] += diffgradx; - e[3][0] += diffgrady; - } - } - - for(i = 0; i < 4; i++) e[i][0] *= 0.5; - -} - - - -/********************************************************************* - * _am_trackFeatureAffine - * - * Tracks a feature point from the image of first occurrence to the actual image. - * - * RETURNS - * KLT_SMALL_DET or KLT_LARGE_RESIDUE or KLT_OOB if feature is lost, - * KLT_TRACKED otherwise. - */ - -/* if you enalbe the DEBUG_AFFINE_MAPPING make sure you have created a directory "./debug" */ -/* #define DEBUG_AFFINE_MAPPING */ - -#ifdef DEBUG_AFFINE_MAPPING -static int counter = 0; -static int glob_index = 0; -#endif - -static int _am_trackFeatureAffine( - float x1, /* location of window in first image */ - float y1, - float *x2, /* starting location of search in second image */ - float *y2, - _KLT_FloatImage img1, - _KLT_FloatImage gradx1, - _KLT_FloatImage grady1, - _KLT_FloatImage img2, - _KLT_FloatImage gradx2, - _KLT_FloatImage grady2, - int width, /* size of window */ - int height, - float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */ - int max_iterations, - float small, /* determinant threshold for declaring KLT_SMALL_DET */ - float th, /* displacement threshold for stopping */ - float th_aff, - float max_residue, /* residue threshold for declaring KLT_LARGE_RESIDUE */ - int lighting_insensitive, /* whether to normalize for gain and bias */ - int affine_map, /* whether to evaluates the consistency of features with affine mapping */ - float mdd, /* difference between the displacements */ - float *Axx, float *Ayx, - float *Axy, float *Ayy) /* used affine mapping */ -{ - - - _FloatWindow imgdiff, gradx, grady; - float gxx, gxy, gyy, ex, ey, dx, dy; - int iteration = 0; - int status = 0; - int hw = width/2; - int hh = height/2; - int nc1 = img1->ncols; - int nr1 = img1->nrows; - int nc2 = img2->ncols; - int nr2 = img2->nrows; - float **a; - float **T; - float one_plus_eps = 1.001f; /* To prevent rounding errors */ - float old_x2 = *x2; - float old_y2 = *y2; - KLT_BOOL convergence = FALSE; - -#ifdef DEBUG_AFFINE_MAPPING - char fname[80]; - _KLT_FloatImage aff_diff_win = _KLTCreateFloatImage(width,height); - printf("starting location x2=%f y2=%f\n", *x2, *y2); -#endif - - /* Allocate memory for windows */ - imgdiff = _allocateFloatWindow(width, height); - gradx = _allocateFloatWindow(width, height); - grady = _allocateFloatWindow(width, height); - T = _am_matrix(6,6); - a = _am_matrix(6,1); - - /* Iteratively update the window position */ - do { - if(!affine_map) { - /* pure translation tracker */ - - /* If out of bounds, exit loop */ - if ( x1-hw < 0.0f || nc1-( x1+hw) < one_plus_eps || - *x2-hw < 0.0f || nc2-(*x2+hw) < one_plus_eps || - y1-hh < 0.0f || nr1-( y1+hh) < one_plus_eps || - *y2-hh < 0.0f || nr2-(*y2+hh) < one_plus_eps) { - status = KLT_OOB; - break; - } - - /* Compute gradient and difference windows */ - if (lighting_insensitive) { - _computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, *x2, *y2, - width, height, imgdiff); - _computeGradientSumLightingInsensitive(gradx1, grady1, gradx2, grady2, - img1, img2, x1, y1, *x2, *y2, width, height, gradx, grady); - } else { - _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2, - width, height, imgdiff); - _computeGradientSum(gradx1, grady1, gradx2, grady2, - x1, y1, *x2, *y2, width, height, gradx, grady); - } - -#ifdef DEBUG_AFFINE_MAPPING - aff_diff_win->data = imgdiff; - sprintf(fname, "./debug/kltimg_trans_diff_win%03d.%03d.pgm", glob_index, counter); - printf("%s\n", fname); - _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); - printf("iter = %d translation tracker res: %f\n", iteration, _sumAbsFloatWindow(imgdiff, width, height)/(width*height)); -#endif - - /* Use these windows to construct matrices */ - _compute2by2GradientMatrix(gradx, grady, width, height, - &gxx, &gxy, &gyy); - _compute2by1ErrorVector(imgdiff, gradx, grady, width, height, step_factor, - &ex, &ey); - - /* Using matrices, solve equation for new displacement */ - status = _solveEquation(gxx, gxy, gyy, ex, ey, small, &dx, &dy); - - convergence = (fabs(dx) < th && fabs(dy) < th); - - *x2 += dx; - *y2 += dy; - - }else{ - /* affine tracker */ - - float ul_x = *Axx * (-hw) + *Axy * hh + *x2; /* upper left corner */ - float ul_y = *Ayx * (-hw) + *Ayy * hh + *y2; - float ll_x = *Axx * (-hw) + *Axy * (-hh) + *x2; /* lower left corner */ - float ll_y = *Ayx * (-hw) + *Ayy * (-hh) + *y2; - float ur_x = *Axx * hw + *Axy * hh + *x2; /* upper right corner */ - float ur_y = *Ayx * hw + *Ayy * hh + *y2; - float lr_x = *Axx * hw + *Axy * (-hh) + *x2; /* lower right corner */ - float lr_y = *Ayx * hw + *Ayy * (-hh) + *y2; - - /* If out of bounds, exit loop */ - if ( x1-hw < 0.0f || nc1-(x1+hw) < one_plus_eps || - y1-hh < 0.0f || nr1-(y1+hh) < one_plus_eps || - ul_x < 0.0f || nc2-(ul_x ) < one_plus_eps || - ll_x < 0.0f || nc2-(ll_x ) < one_plus_eps || - ur_x < 0.0f || nc2-(ur_x ) < one_plus_eps || - lr_x < 0.0f || nc2-(lr_x ) < one_plus_eps || - ul_y < 0.0f || nr2-(ul_y ) < one_plus_eps || - ll_y < 0.0f || nr2-(ll_y ) < one_plus_eps || - ur_y < 0.0f || nr2-(ur_y ) < one_plus_eps || - lr_y < 0.0f || nr2-(lr_y ) < one_plus_eps) { - status = KLT_OOB; - break; - } - -#ifdef DEBUG_AFFINE_MAPPING - counter++; - _am_computeAffineMappedImage(img1, x1, y1, 1.0, 0.0 , 0.0, 1.0, width, height, imgdiff); - aff_diff_win->data = imgdiff; - sprintf(fname, "./debug/kltimg_aff_diff_win%03d.%03d_1.pgm", glob_index, counter); - printf("%s\n", fname); - _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); - - _am_computeAffineMappedImage(img2, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy, width, height, imgdiff); - aff_diff_win->data = imgdiff; - sprintf(fname, "./debug/kltimg_aff_diff_win%03d.%03d_2.pgm", glob_index, counter); - printf("%s\n", fname); - _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); -#endif - - _am_computeIntensityDifferenceAffine(img1, img2, x1, y1, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy, - width, height, imgdiff); -#ifdef DEBUG_AFFINE_MAPPING - aff_diff_win->data = imgdiff; - sprintf(fname, "./debug/kltimg_aff_diff_win%03d.%03d_3.pgm", glob_index,counter); - printf("%s\n", fname); - _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); - - printf("iter = %d affine tracker res: %f\n", iteration, _sumAbsFloatWindow(imgdiff, width, height)/(width*height)); -#endif - - _am_getGradientWinAffine(gradx2, grady2, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy, - width, height, gradx, grady); - - switch(affine_map){ - case 1: - _am_compute4by1ErrorVector(imgdiff, gradx, grady, width, height, a); - _am_compute4by4GradientMatrix(gradx, grady, width, height, T); - - status = _am_gauss_jordan_elimination(T,4,a,1); - - *Axx += a[0][0]; - *Ayx += a[1][0]; - *Ayy = *Axx; - *Axy = -(*Ayx); - - dx = a[2][0]; - dy = a[3][0]; - - break; - case 2: - _am_compute6by1ErrorVector(imgdiff, gradx, grady, width, height, a); - _am_compute6by6GradientMatrix(gradx, grady, width, height, T); - - status = _am_gauss_jordan_elimination(T,6,a,1); - - *Axx += a[0][0]; - *Ayx += a[1][0]; - *Axy += a[2][0]; - *Ayy += a[3][0]; - - dx = a[4][0]; - dy = a[5][0]; - - break; - } - - *x2 += dx; - *y2 += dy; - - /* old upper left corner - new upper left corner */ - ul_x -= *Axx * (-hw) + *Axy * hh + *x2; - ul_y -= *Ayx * (-hw) + *Ayy * hh + *y2; - /* old lower left corner - new lower left corner */ - ll_x -= *Axx * (-hw) + *Axy * (-hh) + *x2; - ll_y -= *Ayx * (-hw) + *Ayy * (-hh) + *y2; - /* old upper right corner - new upper right corner */ - ur_x -= *Axx * hw + *Axy * hh + *x2; - ur_y -= *Ayx * hw + *Ayy * hh + *y2; - /* old lower right corner - new lower right corner */ - lr_x -= *Axx * hw + *Axy * (-hh) + *x2; - lr_y -= *Ayx * hw + *Ayy * (-hh) + *y2; - -#ifdef DEBUG_AFFINE_MAPPING - printf ("iter = %d, ul_x=%f ul_y=%f ll_x=%f ll_y=%f ur_x=%f ur_y=%f lr_x=%f lr_y=%f \n", - iteration, ul_x, ul_y, ll_x, ll_y, ur_x, ur_y, lr_x, lr_y); -#endif - - convergence = (fabs(dx) < th && fabs(dy) < th && - fabs(ul_x) < th_aff && fabs(ul_y) < th_aff && - fabs(ll_x) < th_aff && fabs(ll_y) < th_aff && - fabs(ur_x) < th_aff && fabs(ur_y) < th_aff && - fabs(lr_x) < th_aff && fabs(lr_y) < th_aff); - } - - if (status == KLT_SMALL_DET) break; - iteration++; -#ifdef DEBUG_AFFINE_MAPPING - printf ("iter = %d, x1=%f, y1=%f, x2=%f, y2=%f, Axx=%f, Ayx=%f , Axy=%f, Ayy=%f \n",iteration, x1, y1, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy); -#endif - } while ( !convergence && iteration < max_iterations); - /*} while ( (fabs(dx)>=th || fabs(dy)>=th || (affine_map && iteration < 8) ) && iteration < max_iterations); */ - _am_free_matrix(T); - _am_free_matrix(a); - - /* Check whether window is out of bounds */ - if (*x2-hw < 0.0f || nc2-(*x2+hw) < one_plus_eps || - *y2-hh < 0.0f || nr2-(*y2+hh) < one_plus_eps) - status = KLT_OOB; - - /* Check whether feature point has moved to much during iteration*/ - if ( (*x2-old_x2) > mdd || (*y2-old_y2) > mdd ) - status = KLT_OOB; - - /* Check whether residue is too large */ - if (status == KLT_TRACKED) { - if(!affine_map){ - _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2, - width, height, imgdiff); - }else{ - _am_computeIntensityDifferenceAffine(img1, img2, x1, y1, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy, - width, height, imgdiff); - } -#ifdef DEBUG_AFFINE_MAPPING - printf("iter = %d final_res = %f\n", iteration, _sumAbsFloatWindow(imgdiff, width, height)/(width*height)); -#endif - if (_sumAbsFloatWindow(imgdiff, width, height)/(width*height) > max_residue) - status = KLT_LARGE_RESIDUE; - } - - /* Free memory */ - free(imgdiff); free(gradx); free(grady); - -#ifdef DEBUG_AFFINE_MAPPING - printf("iter = %d status=%d\n", iteration, status); - _KLTFreeFloatImage( aff_diff_win ); -#endif - - /* Return appropriate value */ - return status; -} - -/* - * CONSISTENCY CHECK OF FEATURES BY AFFINE MAPPING (END) - **********************************************************************/ - - - -/********************************************************************* - * KLTTrackFeatures - * - * Tracks feature points from one image to the next. - */ - -void KLTTrackFeatures( - KLT_TrackingContext tc, - KLT_PixelType *img1, - KLT_PixelType *img2, - int ncols, - int nrows, - KLT_FeatureList featurelist) -{ - _KLT_FloatImage tmpimg, floatimg1, floatimg2; - _KLT_Pyramid pyramid1, pyramid1_gradx, pyramid1_grady, - pyramid2, pyramid2_gradx, pyramid2_grady; - float subsampling = (float) tc->subsampling; - float xloc, yloc, xlocout, ylocout; - int val; - int indx, r; - KLT_BOOL floatimg1_created = FALSE; - int i; - - if (KLT_verbose >= 1) { - fprintf(stderr, "(KLT) Tracking %d features in a %d by %d image... ", - KLTCountRemainingFeatures(featurelist), ncols, nrows); - fflush(stderr); - } - - /* Check window size (and correct if necessary) */ - if (tc->window_width % 2 != 1) { - tc->window_width = tc->window_width+1; - KLTWarning("Tracking context's window width must be odd. " - "Changing to %d.\n", tc->window_width); - } - if (tc->window_height % 2 != 1) { - tc->window_height = tc->window_height+1; - KLTWarning("Tracking context's window height must be odd. " - "Changing to %d.\n", tc->window_height); - } - if (tc->window_width < 3) { - tc->window_width = 3; - KLTWarning("Tracking context's window width must be at least three. \n" - "Changing to %d.\n", tc->window_width); - } - if (tc->window_height < 3) { - tc->window_height = 3; - KLTWarning("Tracking context's window height must be at least three. \n" - "Changing to %d.\n", tc->window_height); - } - - /* Create temporary image */ - tmpimg = _KLTCreateFloatImage(ncols, nrows); - - /* Process first image by converting to float, smoothing, computing */ - /* pyramid, and computing gradient pyramids */ - if (tc->sequentialMode && tc->pyramid_last != NULL) { - pyramid1 = (_KLT_Pyramid) tc->pyramid_last; - pyramid1_gradx = (_KLT_Pyramid) tc->pyramid_last_gradx; - pyramid1_grady = (_KLT_Pyramid) tc->pyramid_last_grady; - if (pyramid1->ncols[0] != ncols || pyramid1->nrows[0] != nrows) { - KLTError("(KLTTrackFeatures) Size of incoming image (%d by %d) " - "is different from size of previous image (%d by %d)\n", - ncols, nrows, pyramid1->ncols[0], pyramid1->nrows[0]); - exit(1); - } - assert(pyramid1_gradx != NULL); - assert(pyramid1_grady != NULL); - } else { - floatimg1_created = TRUE; - floatimg1 = _KLTCreateFloatImage(ncols, nrows); - _KLTToFloatImage(img1, ncols, nrows, tmpimg); - _KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg1); - pyramid1 = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - _KLTComputePyramid(floatimg1, pyramid1, tc->pyramid_sigma_fact); - pyramid1_gradx = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - pyramid1_grady = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - for (i = 0 ; i < tc->nPyramidLevels ; i++) - _KLTComputeGradients(pyramid1->img[i], tc->grad_sigma, - pyramid1_gradx->img[i], - pyramid1_grady->img[i]); - } - - /* Do the same thing with second image */ - floatimg2 = _KLTCreateFloatImage(ncols, nrows); - _KLTToFloatImage(img2, ncols, nrows, tmpimg); - _KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg2); - pyramid2 = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - _KLTComputePyramid(floatimg2, pyramid2, tc->pyramid_sigma_fact); - pyramid2_gradx = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - pyramid2_grady = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); - for (i = 0 ; i < tc->nPyramidLevels ; i++) - _KLTComputeGradients(pyramid2->img[i], tc->grad_sigma, - pyramid2_gradx->img[i], - pyramid2_grady->img[i]); - - /* Write internal images */ - if (tc->writeInternalImages) { - char fname[80]; - for (i = 0 ; i < tc->nPyramidLevels ; i++) { - sprintf(fname, "kltimg_tf_i%d.pgm", i); - _KLTWriteFloatImageToPGM(pyramid1->img[i], fname); - sprintf(fname, "kltimg_tf_i%d_gx.pgm", i); - _KLTWriteFloatImageToPGM(pyramid1_gradx->img[i], fname); - sprintf(fname, "kltimg_tf_i%d_gy.pgm", i); - _KLTWriteFloatImageToPGM(pyramid1_grady->img[i], fname); - sprintf(fname, "kltimg_tf_j%d.pgm", i); - _KLTWriteFloatImageToPGM(pyramid2->img[i], fname); - sprintf(fname, "kltimg_tf_j%d_gx.pgm", i); - _KLTWriteFloatImageToPGM(pyramid2_gradx->img[i], fname); - sprintf(fname, "kltimg_tf_j%d_gy.pgm", i); - _KLTWriteFloatImageToPGM(pyramid2_grady->img[i], fname); - } - } - - /* For each feature, do ... */ - for (indx = 0 ; indx < featurelist->nFeatures ; indx++) { - - /* Only track features that are not lost */ - if (featurelist->feature[indx]->val >= 0) { - - xloc = featurelist->feature[indx]->x; - yloc = featurelist->feature[indx]->y; - - /* Transform location to coarsest resolution */ - for (r = tc->nPyramidLevels - 1 ; r >= 0 ; r--) { - xloc /= subsampling; yloc /= subsampling; - } - xlocout = xloc; ylocout = yloc; - - /* Beginning with coarsest resolution, do ... */ - for (r = tc->nPyramidLevels - 1 ; r >= 0 ; r--) { - - /* Track feature at current resolution */ - xloc *= subsampling; yloc *= subsampling; - xlocout *= subsampling; ylocout *= subsampling; - - val = _trackFeature(xloc, yloc, - &xlocout, &ylocout, - pyramid1->img[r], - pyramid1_gradx->img[r], pyramid1_grady->img[r], - pyramid2->img[r], - pyramid2_gradx->img[r], pyramid2_grady->img[r], - tc->window_width, tc->window_height, - tc->step_factor, - tc->max_iterations, - tc->min_determinant, - tc->min_displacement, - tc->max_residue, - tc->lighting_insensitive); - - if (val==KLT_SMALL_DET || val==KLT_OOB) - break; - } - - /* Record feature */ - if (val == KLT_OOB) { - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->val = KLT_OOB; - if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); - if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); - if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); - featurelist->feature[indx]->aff_img = NULL; - featurelist->feature[indx]->aff_img_gradx = NULL; - featurelist->feature[indx]->aff_img_grady = NULL; - - } else if (_outOfBounds(xlocout, ylocout, ncols, nrows, tc->borderx, tc->bordery)) { - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->val = KLT_OOB; - if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); - if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); - if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); - featurelist->feature[indx]->aff_img = NULL; - featurelist->feature[indx]->aff_img_gradx = NULL; - featurelist->feature[indx]->aff_img_grady = NULL; - } else if (val == KLT_SMALL_DET) { - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->val = KLT_SMALL_DET; - if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); - if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); - if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); - featurelist->feature[indx]->aff_img = NULL; - featurelist->feature[indx]->aff_img_gradx = NULL; - featurelist->feature[indx]->aff_img_grady = NULL; - } else if (val == KLT_LARGE_RESIDUE) { - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->val = KLT_LARGE_RESIDUE; - if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); - if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); - if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); - featurelist->feature[indx]->aff_img = NULL; - featurelist->feature[indx]->aff_img_gradx = NULL; - featurelist->feature[indx]->aff_img_grady = NULL; - } else if (val == KLT_MAX_ITERATIONS) { - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->val = KLT_MAX_ITERATIONS; - if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); - if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); - if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); - featurelist->feature[indx]->aff_img = NULL; - featurelist->feature[indx]->aff_img_gradx = NULL; - featurelist->feature[indx]->aff_img_grady = NULL; - } else { - featurelist->feature[indx]->x = xlocout; - featurelist->feature[indx]->y = ylocout; - featurelist->feature[indx]->val = KLT_TRACKED; - if (tc->affineConsistencyCheck >= 0 && val == KLT_TRACKED) { /*for affine mapping*/ - int border = 2; /* add border for interpolation */ - -#ifdef DEBUG_AFFINE_MAPPING - glob_index = indx; -#endif - - if(!featurelist->feature[indx]->aff_img){ - /* save image and gradient for each feature at finest resolution after first successful track */ - featurelist->feature[indx]->aff_img = _KLTCreateFloatImage((tc->affine_window_width+border), (tc->affine_window_height+border)); - featurelist->feature[indx]->aff_img_gradx = _KLTCreateFloatImage((tc->affine_window_width+border), (tc->affine_window_height+border)); - featurelist->feature[indx]->aff_img_grady = _KLTCreateFloatImage((tc->affine_window_width+border), (tc->affine_window_height+border)); - _am_getSubFloatImage(pyramid1->img[0],xloc,yloc,featurelist->feature[indx]->aff_img); - _am_getSubFloatImage(pyramid1_gradx->img[0],xloc,yloc,featurelist->feature[indx]->aff_img_gradx); - _am_getSubFloatImage(pyramid1_grady->img[0],xloc,yloc,featurelist->feature[indx]->aff_img_grady); - featurelist->feature[indx]->aff_x = xloc - (int) xloc + (tc->affine_window_width+border)/2; - featurelist->feature[indx]->aff_y = yloc - (int) yloc + (tc->affine_window_height+border)/2;; - }else{ - /* affine tracking */ - val = _am_trackFeatureAffine(featurelist->feature[indx]->aff_x, featurelist->feature[indx]->aff_y, - &xlocout, &ylocout, - featurelist->feature[indx]->aff_img, - featurelist->feature[indx]->aff_img_gradx, - featurelist->feature[indx]->aff_img_grady, - pyramid2->img[0], - pyramid2_gradx->img[0], pyramid2_grady->img[0], - tc->affine_window_width, tc->affine_window_height, - tc->step_factor, - tc->affine_max_iterations, - tc->min_determinant, - tc->min_displacement, - tc->affine_min_displacement, - tc->affine_max_residue, - tc->lighting_insensitive, - tc->affineConsistencyCheck, - tc->affine_max_displacement_differ, - &featurelist->feature[indx]->aff_Axx, - &featurelist->feature[indx]->aff_Ayx, - &featurelist->feature[indx]->aff_Axy, - &featurelist->feature[indx]->aff_Ayy - ); - featurelist->feature[indx]->val = val; - if(val != KLT_TRACKED){ - featurelist->feature[indx]->x = -1.0; - featurelist->feature[indx]->y = -1.0; - featurelist->feature[indx]->aff_x = -1.0; - featurelist->feature[indx]->aff_y = -1.0; - /* free image and gradient for lost feature */ - _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); - _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); - _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); - featurelist->feature[indx]->aff_img = NULL; - featurelist->feature[indx]->aff_img_gradx = NULL; - featurelist->feature[indx]->aff_img_grady = NULL; - }else{ - /*featurelist->feature[indx]->x = xlocout;*/ - /*featurelist->feature[indx]->y = ylocout;*/ - } - } - } - - } - } - } - - if (tc->sequentialMode) { - tc->pyramid_last = pyramid2; - tc->pyramid_last_gradx = pyramid2_gradx; - tc->pyramid_last_grady = pyramid2_grady; - } else { - _KLTFreePyramid(pyramid2); - _KLTFreePyramid(pyramid2_gradx); - _KLTFreePyramid(pyramid2_grady); - } - - /* Free memory */ - _KLTFreeFloatImage(tmpimg); - if (floatimg1_created) _KLTFreeFloatImage(floatimg1); - _KLTFreeFloatImage(floatimg2); - _KLTFreePyramid(pyramid1); - _KLTFreePyramid(pyramid1_gradx); - _KLTFreePyramid(pyramid1_grady); - - if (KLT_verbose >= 1) { - fprintf(stderr, "\n\t%d features successfully tracked.\n", - KLTCountRemainingFeatures(featurelist)); - if (tc->writeInternalImages) - fprintf(stderr, "\tWrote images to 'kltimg_tf*.pgm'.\n"); - fflush(stderr); - } - -} - - +/********************************************************************* + * trackFeatures.c + * + *********************************************************************/ + +/* Standard includes */ +#include +#include /* fabs() */ +#include /* malloc() */ +#include /* fflush() */ + +/* Our includes */ +#include "base.h" +#include "error.h" +#include "convolve.h" /* for computing pyramid */ +#include "klt.h" +#include "klt_util.h" /* _KLT_FloatImage */ +#include "pyramid.h" /* _KLT_Pyramid */ + +extern int KLT_verbose; + +typedef float *_FloatWindow; + +/********************************************************************* + * _interpolate + * + * Given a point (x,y) in an image, computes the bilinear interpolated + * gray-level value of the point in the image. + */ + +static float _interpolate( + float x, + float y, + _KLT_FloatImage img) +{ + int xt = (int) x; /* coordinates of top-left corner */ + int yt = (int) y; + float ax = x - xt; + float ay = y - yt; + float *ptr = img->data + (img->ncols*yt) + xt; + +#ifndef _DNDEBUG + if (xt<0 || yt<0 || xt>=img->ncols-1 || yt>=img->nrows-1) { + fprintf(stderr, "(xt,yt)=(%d,%d) imgsize=(%d,%d)\n" + "(x,y)=(%f,%f) (ax,ay)=(%f,%f)\n", + xt, yt, img->ncols, img->nrows, x, y, ax, ay); + fflush(stderr); + } +#endif + + assert (xt >= 0 && yt >= 0 && xt <= img->ncols - 2 && yt <= img->nrows - 2); + + return ( (1-ax) * (1-ay) * *ptr + + ax * (1-ay) * *(ptr+1) + + (1-ax) * ay * *(ptr+(img->ncols)) + + ax * ay * *(ptr+(img->ncols)+1) ); +} + + +/********************************************************************* + * _computeIntensityDifference + * + * Given two images and the window center in both images, + * aligns the images wrt the window and computes the difference + * between the two overlaid images. + */ + +static void _computeIntensityDifference( + _KLT_FloatImage img1, /* images */ + _KLT_FloatImage img2, + float x1, float y1, /* center of window in 1st img */ + float x2, float y2, /* center of window in 2nd img */ + int width, int height, /* size of window */ + _FloatWindow imgdiff) /* output */ +{ + int hw = width/2, hh = height/2; + float g1, g2; + int i, j; + + /* Compute values */ + for (j = -hh ; j <= hh ; j++) + for (i = -hw ; i <= hw ; i++) { + g1 = _interpolate(x1+i, y1+j, img1); + g2 = _interpolate(x2+i, y2+j, img2); + *imgdiff++ = g1 - g2; + } +} + + +/********************************************************************* + * _computeGradientSum + * + * Given two gradients and the window center in both images, + * aligns the gradients wrt the window and computes the sum of the two + * overlaid gradients. + */ + +static void _computeGradientSum( + _KLT_FloatImage gradx1, /* gradient images */ + _KLT_FloatImage grady1, + _KLT_FloatImage gradx2, + _KLT_FloatImage grady2, + float x1, float y1, /* center of window in 1st img */ + float x2, float y2, /* center of window in 2nd img */ + int width, int height, /* size of window */ + _FloatWindow gradx, /* output */ + _FloatWindow grady) /* " */ +{ + int hw = width/2, hh = height/2; + float g1, g2; + int i, j; + + /* Compute values */ + for (j = -hh ; j <= hh ; j++) + for (i = -hw ; i <= hw ; i++) { + g1 = _interpolate(x1+i, y1+j, gradx1); + g2 = _interpolate(x2+i, y2+j, gradx2); + *gradx++ = g1 + g2; + g1 = _interpolate(x1+i, y1+j, grady1); + g2 = _interpolate(x2+i, y2+j, grady2); + *grady++ = g1 + g2; + } +} + +/********************************************************************* + * _computeIntensityDifferenceLightingInsensitive + * + * Given two images and the window center in both images, + * aligns the images wrt the window and computes the difference + * between the two overlaid images; normalizes for overall gain and bias. + */ + +static void _computeIntensityDifferenceLightingInsensitive( + _KLT_FloatImage img1, /* images */ + _KLT_FloatImage img2, + float x1, float y1, /* center of window in 1st img */ + float x2, float y2, /* center of window in 2nd img */ + int width, int height, /* size of window */ + _FloatWindow imgdiff) /* output */ +{ + int hw = width/2, hh = height/2; + float g1, g2, sum1_squared = 0, sum2_squared = 0; + int i, j; + + float sum1 = 0, sum2 = 0; + float mean1, mean2,alpha,belta; + /* Compute values */ + for (j = -hh ; j <= hh ; j++) + for (i = -hw ; i <= hw ; i++) { + g1 = _interpolate(x1+i, y1+j, img1); + g2 = _interpolate(x2+i, y2+j, img2); + sum1 += g1; sum2 += g2; + sum1_squared += g1*g1; + sum2_squared += g2*g2; + } + mean1=sum1_squared/(width*height); + mean2=sum2_squared/(width*height); + alpha = (float) sqrt(mean1/mean2); + mean1=sum1/(width*height); + mean2=sum2/(width*height); + belta = mean1-alpha*mean2; + + for (j = -hh ; j <= hh ; j++) + for (i = -hw ; i <= hw ; i++) { + g1 = _interpolate(x1+i, y1+j, img1); + g2 = _interpolate(x2+i, y2+j, img2); + *imgdiff++ = g1- g2*alpha-belta; + } +} + + +/********************************************************************* + * _computeGradientSumLightingInsensitive + * + * Given two gradients and the window center in both images, + * aligns the gradients wrt the window and computes the sum of the two + * overlaid gradients; normalizes for overall gain and bias. + */ + +static void _computeGradientSumLightingInsensitive( + _KLT_FloatImage gradx1, /* gradient images */ + _KLT_FloatImage grady1, + _KLT_FloatImage gradx2, + _KLT_FloatImage grady2, + _KLT_FloatImage img1, /* images */ + _KLT_FloatImage img2, + + float x1, float y1, /* center of window in 1st img */ + float x2, float y2, /* center of window in 2nd img */ + int width, int height, /* size of window */ + _FloatWindow gradx, /* output */ + _FloatWindow grady) /* " */ +{ + int hw = width/2, hh = height/2; + float g1, g2, sum1_squared = 0, sum2_squared = 0; + int i, j; + + float mean1, mean2, alpha; + for (j = -hh ; j <= hh ; j++) + for (i = -hw ; i <= hw ; i++) { + g1 = _interpolate(x1+i, y1+j, img1); + g2 = _interpolate(x2+i, y2+j, img2); + sum1_squared += g1; sum2_squared += g2; + } + mean1 = sum1_squared/(width*height); + mean2 = sum2_squared/(width*height); + alpha = (float) sqrt(mean1/mean2); + + /* Compute values */ + for (j = -hh ; j <= hh ; j++) + for (i = -hw ; i <= hw ; i++) { + g1 = _interpolate(x1+i, y1+j, gradx1); + g2 = _interpolate(x2+i, y2+j, gradx2); + *gradx++ = g1 + g2*alpha; + g1 = _interpolate(x1+i, y1+j, grady1); + g2 = _interpolate(x2+i, y2+j, grady2); + *grady++ = g1+ g2*alpha; + } +} + +/********************************************************************* + * _compute2by2GradientMatrix + * + */ + +static void _compute2by2GradientMatrix( + _FloatWindow gradx, + _FloatWindow grady, + int width, /* size of window */ + int height, + float *gxx, /* return values */ + float *gxy, + float *gyy) + +{ + float gx, gy; + int i; + + /* Compute values */ + *gxx = 0.0; *gxy = 0.0; *gyy = 0.0; + for (i = 0 ; i < width * height ; i++) { + gx = *gradx++; + gy = *grady++; + *gxx += gx*gx; + *gxy += gx*gy; + *gyy += gy*gy; + } +} + + +/********************************************************************* + * _compute2by1ErrorVector + * + */ + +static void _compute2by1ErrorVector( + _FloatWindow imgdiff, + _FloatWindow gradx, + _FloatWindow grady, + int width, /* size of window */ + int height, + float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */ + float *ex, /* return values */ + float *ey) +{ + float diff; + int i; + + /* Compute values */ + *ex = 0; *ey = 0; + for (i = 0 ; i < width * height ; i++) { + diff = *imgdiff++; + *ex += diff * (*gradx++); + *ey += diff * (*grady++); + } + *ex *= step_factor; + *ey *= step_factor; +} + + +/********************************************************************* + * _solveEquation + * + * Solves the 2x2 matrix equation + * [gxx gxy] [dx] = [ex] + * [gxy gyy] [dy] = [ey] + * for dx and dy. + * + * Returns KLT_TRACKED on success and KLT_SMALL_DET on failure + */ + +static int _solveEquation( + float gxx, float gxy, float gyy, + float ex, float ey, + float small, + float *dx, float *dy) +{ + float det = gxx*gyy - gxy*gxy; + + + if (det < small) return KLT_SMALL_DET; + + *dx = (gyy*ex - gxy*ey)/det; + *dy = (gxx*ey - gxy*ex)/det; + return KLT_TRACKED; +} + + +/********************************************************************* + * _allocateFloatWindow + */ + +static _FloatWindow _allocateFloatWindow( + int width, + int height) +{ + _FloatWindow fw; + + fw = (_FloatWindow) malloc(width*height*sizeof(float)); + if (fw == NULL) { + KLTError("(_allocateFloatWindow) Out of memory."); + exit(1); + } + return fw; +} + + +/********************************************************************* + * _printFloatWindow + * (for debugging purposes) + */ + +/* +static void _printFloatWindow( + _FloatWindow fw, + int width, + int height) +{ + int i, j; + + fprintf(stderr, "\n"); + for (i = 0 ; i < width ; i++) { + for (j = 0 ; j < height ; j++) { + fprintf(stderr, "%6.1f ", *fw++); + } + fprintf(stderr, "\n"); + } +} +*/ + + +/********************************************************************* + * _sumAbsFloatWindow + */ + +static float _sumAbsFloatWindow( + _FloatWindow fw, + int width, + int height) +{ + float sum = 0.0; + int w; + + for ( ; height > 0 ; height--) + for (w=0 ; w < width ; w++) + sum += (float) fabs(*fw++); + + return sum; +} + + +/********************************************************************* + * _trackFeature + * + * Tracks a feature point from one image to the next. + * + * RETURNS + * KLT_SMALL_DET if feature is lost, + * KLT_MAX_ITERATIONS if tracking stopped because iterations timed out, + * KLT_TRACKED otherwise. + */ + +static int _trackFeature( + float x1, /* location of window in first image */ + float y1, + float *x2, /* starting location of search in second image */ + float *y2, + _KLT_FloatImage img1, + _KLT_FloatImage gradx1, + _KLT_FloatImage grady1, + _KLT_FloatImage img2, + _KLT_FloatImage gradx2, + _KLT_FloatImage grady2, + int width, /* size of window */ + int height, + float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */ + int max_iterations, + float small, /* determinant threshold for declaring KLT_SMALL_DET */ + float th, /* displacement threshold for stopping */ + float max_residue, /* residue threshold for declaring KLT_LARGE_RESIDUE */ + int lighting_insensitive) /* whether to normalize for gain and bias */ +{ + _FloatWindow imgdiff, gradx, grady; + float gxx, gxy, gyy, ex, ey, dx, dy; + int iteration = 0; + int status; + int hw = width/2; + int hh = height/2; + int nc = img1->ncols; + int nr = img1->nrows; + float one_plus_eps = 1.001f; /* To prevent rounding errors */ + + + /* Allocate memory for windows */ + imgdiff = _allocateFloatWindow(width, height); + gradx = _allocateFloatWindow(width, height); + grady = _allocateFloatWindow(width, height); + + /* Iteratively update the window position */ + do { + + /* If out of bounds, exit loop */ + if ( x1-hw < 0.0f || nc-( x1+hw) < one_plus_eps || + *x2-hw < 0.0f || nc-(*x2+hw) < one_plus_eps || + y1-hh < 0.0f || nr-( y1+hh) < one_plus_eps || + *y2-hh < 0.0f || nr-(*y2+hh) < one_plus_eps) { + status = KLT_OOB; + break; + } + + /* Compute gradient and difference windows */ + if (lighting_insensitive) { + _computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, *x2, *y2, + width, height, imgdiff); + _computeGradientSumLightingInsensitive(gradx1, grady1, gradx2, grady2, + img1, img2, x1, y1, *x2, *y2, width, height, gradx, grady); + } else { + _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2, + width, height, imgdiff); + _computeGradientSum(gradx1, grady1, gradx2, grady2, + x1, y1, *x2, *y2, width, height, gradx, grady); + } + + + /* Use these windows to construct matrices */ + _compute2by2GradientMatrix(gradx, grady, width, height, + &gxx, &gxy, &gyy); + _compute2by1ErrorVector(imgdiff, gradx, grady, width, height, step_factor, + &ex, &ey); + + /* Using matrices, solve equation for new displacement */ + status = _solveEquation(gxx, gxy, gyy, ex, ey, small, &dx, &dy); + if (status == KLT_SMALL_DET) break; + + *x2 += dx; + *y2 += dy; + iteration++; + + } while ((fabs(dx)>=th || fabs(dy)>=th) && iteration < max_iterations); + + /* Check whether window is out of bounds */ + if (*x2-hw < 0.0f || nc-(*x2+hw) < one_plus_eps || + *y2-hh < 0.0f || nr-(*y2+hh) < one_plus_eps) + status = KLT_OOB; + + /* Check whether residue is too large */ + if (status == KLT_TRACKED) { + if (lighting_insensitive) + _computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, *x2, *y2, + width, height, imgdiff); + else + _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2, + width, height, imgdiff); + if (_sumAbsFloatWindow(imgdiff, width, height)/(width*height) > max_residue) + status = KLT_LARGE_RESIDUE; + } + + /* Free memory */ + free(imgdiff); free(gradx); free(grady); + + /* Return appropriate value */ + if (status == KLT_SMALL_DET) return KLT_SMALL_DET; + else if (status == KLT_OOB) return KLT_OOB; + else if (status == KLT_LARGE_RESIDUE) return KLT_LARGE_RESIDUE; + else if (iteration >= max_iterations) return KLT_MAX_ITERATIONS; + else return KLT_TRACKED; + +} + + +/*********************************************************************/ + +static KLT_BOOL _outOfBounds( + float x, + float y, + int ncols, + int nrows, + int borderx, + int bordery) +{ + return (x < borderx || x > ncols-1-borderx || + y < bordery || y > nrows-1-bordery ); +} + + + + +/********************************************************************** +* CONSISTENCY CHECK OF FEATURES BY AFFINE MAPPING (BEGIN) +* +* Created by: Thorsten Thormaehlen (University of Hannover) June 2004 +* thormae@tnt.uni-hannover.de +* +* Permission is granted to any individual or institution to use, copy, modify, +* and distribute this part of the software, provided that this complete authorship +* and permission notice is maintained, intact, in all copies. +* +* This software is provided "as is" without express or implied warranty. +* +* +* The following static functions are helpers for the affine mapping. +* They all start with "_am". +* There are also small changes in other files for the +* affine mapping these are all marked by "for affine mapping" +* +* Thanks to Kevin Koeser (koeser@mip.informatik.uni-kiel.de) for fixing a bug +*/ + +#define SWAP_ME(X,Y) {temp=(X);(X)=(Y);(Y)=temp;} + +static float **_am_matrix(long nr, long nc) +{ + float **m; + int a; + m = (float **) malloc((size_t)(nr*sizeof(float*))); + m[0] = (float *) malloc((size_t)((nr*nc)*sizeof(float))); + for(a = 1; a < nr; a++) m[a] = m[a-1]+nc; + return m; +} + +static void _am_free_matrix(float **m) +{ + free(m[0]); + free(m); +} + + +static int _am_gauss_jordan_elimination(float **a, int n, float **b, int m) +{ + /* re-implemented from Numerical Recipes in C */ + int *indxc,*indxr,*ipiv; + int i,j,k,l,ll; + float big,dum,pivinv,temp; + int col = 0; + int row = 0; + + indxc=(int *)malloc((size_t) (n*sizeof(int))); + indxr=(int *)malloc((size_t) (n*sizeof(int))); + ipiv=(int *)malloc((size_t) (n*sizeof(int))); + for (j=0;j= big) { + big= (float) fabs(a[j][k]); + row=j; + col=k; + } + } else if (ipiv[k] > 1) { + free(ipiv); free(indxr); free(indxc); return KLT_SMALL_DET; + } + } + ++(ipiv[col]); + if (row != col) { + for (l=0;l=0;l--) { + if (indxr[l] != indxc[l]) + for (k=0;kncols/2, hh = window->nrows/2; + int x0 = (int) x; + int y0 = (int) y; + float * windata = window->data; + int offset; + int i, j; + + assert(x0 - hw >= 0); + assert(y0 - hh >= 0); + assert(x0 + hw <= img->ncols); + assert(y0 + hh <= img->nrows); + + /* copy values */ + for (j = -hh ; j <= hh ; j++) + for (i = -hw ; i <= hw ; i++) { + offset = (j+y0)*img->ncols + (i+x0); + *windata++ = *(img->data+offset); + } +} + +/********************************************************************* + * _am_computeIntensityDifferenceAffine + * + * Given two images and the window center in both images, + * aligns the images with the window and computes the difference + * between the two overlaid images using the affine mapping. + * A = [ Axx Axy] + * [ Ayx Ayy] +*/ + +static void _am_computeIntensityDifferenceAffine( + _KLT_FloatImage img1, /* images */ + _KLT_FloatImage img2, + float x1, float y1, /* center of window in 1st img */ + float x2, float y2, /* center of window in 2nd img */ + float Axx, float Ayx , float Axy, float Ayy, /* affine mapping */ + int width, int height, /* size of window */ + _FloatWindow imgdiff) /* output */ +{ + int hw = width/2, hh = height/2; + float g1, g2; + int i, j; + float mi, mj; + + /* Compute values */ + for (j = -hh ; j <= hh ; j++) + for (i = -hw ; i <= hw ; i++) { + g1 = _interpolate(x1+i, y1+j, img1); + mi = Axx * i + Axy * j; + mj = Ayx * i + Ayy * j; + g2 = _interpolate(x2+mi, y2+mj, img2); + *imgdiff++ = g1 - g2; + } +} + +/********************************************************************* + * _am_compute6by6GradientMatrix + * + */ + +static void _am_compute6by6GradientMatrix( + _FloatWindow gradx, + _FloatWindow grady, + int width, /* size of window */ + int height, + float **T) /* return values */ +{ + int hw = width/2, hh = height/2; + int i, j; + float gx, gy, gxx, gxy, gyy, x, y, xx, xy, yy; + + + /* Set values to zero */ + for (j = 0 ; j < 6 ; j++) { + for (i = j ; i < 6 ; i++) { + T[j][i] = 0.0; + } + } + + for (j = -hh ; j <= hh ; j++) { + for (i = -hw ; i <= hw ; i++) { + gx = *gradx++; + gy = *grady++; + gxx = gx * gx; + gxy = gx * gy; + gyy = gy * gy; + x = (float) i; + y = (float) j; + xx = x * x; + xy = x * y; + yy = y * y; + + T[0][0] += xx * gxx; + T[0][1] += xx * gxy; + T[0][2] += xy * gxx; + T[0][3] += xy * gxy; + T[0][4] += x * gxx; + T[0][5] += x * gxy; + + T[1][1] += xx * gyy; + T[1][2] += xy * gxy; + T[1][3] += xy * gyy; + T[1][4] += x * gxy; + T[1][5] += x * gyy; + + T[2][2] += yy * gxx; + T[2][3] += yy * gxy; + T[2][4] += y * gxx; + T[2][5] += y * gxy; + + T[3][3] += yy * gyy; + T[3][4] += y * gxy; + T[3][5] += y * gyy; + + T[4][4] += gxx; + T[4][5] += gxy; + + T[5][5] += gyy; + } + } + + for (j = 0 ; j < 5 ; j++) { + for (i = j+1 ; i < 6 ; i++) { + T[i][j] = T[j][i]; + } + } + +} + + + +/********************************************************************* + * _am_compute6by1ErrorVector + * + */ + +static void _am_compute6by1ErrorVector( + _FloatWindow imgdiff, + _FloatWindow gradx, + _FloatWindow grady, + int width, /* size of window */ + int height, + float **e) /* return values */ +{ + int hw = width/2, hh = height/2; + int i, j; + float diff, diffgradx, diffgrady; + + /* Set values to zero */ + for(i = 0; i < 6; i++) e[i][0] = 0.0; + + /* Compute values */ + for (j = -hh ; j <= hh ; j++) { + for (i = -hw ; i <= hw ; i++) { + diff = *imgdiff++; + diffgradx = diff * (*gradx++); + diffgrady = diff * (*grady++); + e[0][0] += diffgradx * i; + e[1][0] += diffgrady * i; + e[2][0] += diffgradx * j; + e[3][0] += diffgrady * j; + e[4][0] += diffgradx; + e[5][0] += diffgrady; + } + } + + for(i = 0; i < 6; i++) e[i][0] *= 0.5; + +} + + +/********************************************************************* + * _am_compute4by4GradientMatrix + * + */ + +static void _am_compute4by4GradientMatrix( + _FloatWindow gradx, + _FloatWindow grady, + int width, /* size of window */ + int height, + float **T) /* return values */ +{ + int hw = width/2, hh = height/2; + int i, j; + float gx, gy, x, y; + + + /* Set values to zero */ + for (j = 0 ; j < 4 ; j++) { + for (i = 0 ; i < 4 ; i++) { + T[j][i] = 0.0; + } + } + + for (j = -hh ; j <= hh ; j++) { + for (i = -hw ; i <= hw ; i++) { + gx = *gradx++; + gy = *grady++; + x = (float) i; + y = (float) j; + T[0][0] += (x*gx+y*gy) * (x*gx+y*gy); + T[0][1] += (x*gx+y*gy)*(x*gy-y*gx); + T[0][2] += (x*gx+y*gy)*gx; + T[0][3] += (x*gx+y*gy)*gy; + + T[1][1] += (x*gy-y*gx) * (x*gy-y*gx); + T[1][2] += (x*gy-y*gx)*gx; + T[1][3] += (x*gy-y*gx)*gy; + + T[2][2] += gx*gx; + T[2][3] += gx*gy; + + T[3][3] += gy*gy; + } + } + + for (j = 0 ; j < 3 ; j++) { + for (i = j+1 ; i < 4 ; i++) { + T[i][j] = T[j][i]; + } + } + +} + +/********************************************************************* + * _am_compute4by1ErrorVector + * + */ + +static void _am_compute4by1ErrorVector( + _FloatWindow imgdiff, + _FloatWindow gradx, + _FloatWindow grady, + int width, /* size of window */ + int height, + float **e) /* return values */ +{ + int hw = width/2, hh = height/2; + int i, j; + float diff, diffgradx, diffgrady; + + /* Set values to zero */ + for(i = 0; i < 4; i++) e[i][0] = 0.0; + + /* Compute values */ + for (j = -hh ; j <= hh ; j++) { + for (i = -hw ; i <= hw ; i++) { + diff = *imgdiff++; + diffgradx = diff * (*gradx++); + diffgrady = diff * (*grady++); + e[0][0] += diffgradx * i + diffgrady * j; + e[1][0] += diffgrady * i - diffgradx * j; + e[2][0] += diffgradx; + e[3][0] += diffgrady; + } + } + + for(i = 0; i < 4; i++) e[i][0] *= 0.5; + +} + + + +/********************************************************************* + * _am_trackFeatureAffine + * + * Tracks a feature point from the image of first occurrence to the actual image. + * + * RETURNS + * KLT_SMALL_DET or KLT_LARGE_RESIDUE or KLT_OOB if feature is lost, + * KLT_TRACKED otherwise. + */ + +/* if you enalbe the DEBUG_AFFINE_MAPPING make sure you have created a directory "./debug" */ +/* #define DEBUG_AFFINE_MAPPING */ + +#ifdef DEBUG_AFFINE_MAPPING +static int counter = 0; +static int glob_index = 0; +#endif + +static int _am_trackFeatureAffine( + float x1, /* location of window in first image */ + float y1, + float *x2, /* starting location of search in second image */ + float *y2, + _KLT_FloatImage img1, + _KLT_FloatImage gradx1, + _KLT_FloatImage grady1, + _KLT_FloatImage img2, + _KLT_FloatImage gradx2, + _KLT_FloatImage grady2, + int width, /* size of window */ + int height, + float step_factor, /* 2.0 comes from equations, 1.0 seems to avoid overshooting */ + int max_iterations, + float small, /* determinant threshold for declaring KLT_SMALL_DET */ + float th, /* displacement threshold for stopping */ + float th_aff, + float max_residue, /* residue threshold for declaring KLT_LARGE_RESIDUE */ + int lighting_insensitive, /* whether to normalize for gain and bias */ + int affine_map, /* whether to evaluates the consistency of features with affine mapping */ + float mdd, /* difference between the displacements */ + float *Axx, float *Ayx, + float *Axy, float *Ayy) /* used affine mapping */ +{ + + + _FloatWindow imgdiff, gradx, grady; + float gxx, gxy, gyy, ex, ey, dx, dy; + int iteration = 0; + int status = 0; + int hw = width/2; + int hh = height/2; + int nc1 = img1->ncols; + int nr1 = img1->nrows; + int nc2 = img2->ncols; + int nr2 = img2->nrows; + float **a; + float **T; + float one_plus_eps = 1.001f; /* To prevent rounding errors */ + float old_x2 = *x2; + float old_y2 = *y2; + KLT_BOOL convergence = FALSE; + +#ifdef DEBUG_AFFINE_MAPPING + char fname[80]; + _KLT_FloatImage aff_diff_win = _KLTCreateFloatImage(width,height); + printf("starting location x2=%f y2=%f\n", *x2, *y2); +#endif + + /* Allocate memory for windows */ + imgdiff = _allocateFloatWindow(width, height); + gradx = _allocateFloatWindow(width, height); + grady = _allocateFloatWindow(width, height); + T = _am_matrix(6,6); + a = _am_matrix(6,1); + + /* Iteratively update the window position */ + do { + if(!affine_map) { + /* pure translation tracker */ + + /* If out of bounds, exit loop */ + if ( x1-hw < 0.0f || nc1-( x1+hw) < one_plus_eps || + *x2-hw < 0.0f || nc2-(*x2+hw) < one_plus_eps || + y1-hh < 0.0f || nr1-( y1+hh) < one_plus_eps || + *y2-hh < 0.0f || nr2-(*y2+hh) < one_plus_eps) { + status = KLT_OOB; + break; + } + + /* Compute gradient and difference windows */ + if (lighting_insensitive) { + _computeIntensityDifferenceLightingInsensitive(img1, img2, x1, y1, *x2, *y2, + width, height, imgdiff); + _computeGradientSumLightingInsensitive(gradx1, grady1, gradx2, grady2, + img1, img2, x1, y1, *x2, *y2, width, height, gradx, grady); + } else { + _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2, + width, height, imgdiff); + _computeGradientSum(gradx1, grady1, gradx2, grady2, + x1, y1, *x2, *y2, width, height, gradx, grady); + } + +#ifdef DEBUG_AFFINE_MAPPING + aff_diff_win->data = imgdiff; + sprintf(fname, "./debug/kltimg_trans_diff_win%03d.%03d.pgm", glob_index, counter); + printf("%s\n", fname); + _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); + printf("iter = %d translation tracker res: %f\n", iteration, _sumAbsFloatWindow(imgdiff, width, height)/(width*height)); +#endif + + /* Use these windows to construct matrices */ + _compute2by2GradientMatrix(gradx, grady, width, height, + &gxx, &gxy, &gyy); + _compute2by1ErrorVector(imgdiff, gradx, grady, width, height, step_factor, + &ex, &ey); + + /* Using matrices, solve equation for new displacement */ + status = _solveEquation(gxx, gxy, gyy, ex, ey, small, &dx, &dy); + + convergence = (fabs(dx) < th && fabs(dy) < th); + + *x2 += dx; + *y2 += dy; + + }else{ + /* affine tracker */ + + float ul_x = *Axx * (-hw) + *Axy * hh + *x2; /* upper left corner */ + float ul_y = *Ayx * (-hw) + *Ayy * hh + *y2; + float ll_x = *Axx * (-hw) + *Axy * (-hh) + *x2; /* lower left corner */ + float ll_y = *Ayx * (-hw) + *Ayy * (-hh) + *y2; + float ur_x = *Axx * hw + *Axy * hh + *x2; /* upper right corner */ + float ur_y = *Ayx * hw + *Ayy * hh + *y2; + float lr_x = *Axx * hw + *Axy * (-hh) + *x2; /* lower right corner */ + float lr_y = *Ayx * hw + *Ayy * (-hh) + *y2; + + /* If out of bounds, exit loop */ + if ( x1-hw < 0.0f || nc1-(x1+hw) < one_plus_eps || + y1-hh < 0.0f || nr1-(y1+hh) < one_plus_eps || + ul_x < 0.0f || nc2-(ul_x ) < one_plus_eps || + ll_x < 0.0f || nc2-(ll_x ) < one_plus_eps || + ur_x < 0.0f || nc2-(ur_x ) < one_plus_eps || + lr_x < 0.0f || nc2-(lr_x ) < one_plus_eps || + ul_y < 0.0f || nr2-(ul_y ) < one_plus_eps || + ll_y < 0.0f || nr2-(ll_y ) < one_plus_eps || + ur_y < 0.0f || nr2-(ur_y ) < one_plus_eps || + lr_y < 0.0f || nr2-(lr_y ) < one_plus_eps) { + status = KLT_OOB; + break; + } + +#ifdef DEBUG_AFFINE_MAPPING + counter++; + _am_computeAffineMappedImage(img1, x1, y1, 1.0, 0.0 , 0.0, 1.0, width, height, imgdiff); + aff_diff_win->data = imgdiff; + sprintf(fname, "./debug/kltimg_aff_diff_win%03d.%03d_1.pgm", glob_index, counter); + printf("%s\n", fname); + _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); + + _am_computeAffineMappedImage(img2, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy, width, height, imgdiff); + aff_diff_win->data = imgdiff; + sprintf(fname, "./debug/kltimg_aff_diff_win%03d.%03d_2.pgm", glob_index, counter); + printf("%s\n", fname); + _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); +#endif + + _am_computeIntensityDifferenceAffine(img1, img2, x1, y1, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy, + width, height, imgdiff); +#ifdef DEBUG_AFFINE_MAPPING + aff_diff_win->data = imgdiff; + sprintf(fname, "./debug/kltimg_aff_diff_win%03d.%03d_3.pgm", glob_index,counter); + printf("%s\n", fname); + _KLTWriteAbsFloatImageToPGM(aff_diff_win, fname,256.0); + + printf("iter = %d affine tracker res: %f\n", iteration, _sumAbsFloatWindow(imgdiff, width, height)/(width*height)); +#endif + + _am_getGradientWinAffine(gradx2, grady2, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy, + width, height, gradx, grady); + + switch(affine_map){ + case 1: + _am_compute4by1ErrorVector(imgdiff, gradx, grady, width, height, a); + _am_compute4by4GradientMatrix(gradx, grady, width, height, T); + + status = _am_gauss_jordan_elimination(T,4,a,1); + + *Axx += a[0][0]; + *Ayx += a[1][0]; + *Ayy = *Axx; + *Axy = -(*Ayx); + + dx = a[2][0]; + dy = a[3][0]; + + break; + case 2: + _am_compute6by1ErrorVector(imgdiff, gradx, grady, width, height, a); + _am_compute6by6GradientMatrix(gradx, grady, width, height, T); + + status = _am_gauss_jordan_elimination(T,6,a,1); + + *Axx += a[0][0]; + *Ayx += a[1][0]; + *Axy += a[2][0]; + *Ayy += a[3][0]; + + dx = a[4][0]; + dy = a[5][0]; + + break; + } + + *x2 += dx; + *y2 += dy; + + /* old upper left corner - new upper left corner */ + ul_x -= *Axx * (-hw) + *Axy * hh + *x2; + ul_y -= *Ayx * (-hw) + *Ayy * hh + *y2; + /* old lower left corner - new lower left corner */ + ll_x -= *Axx * (-hw) + *Axy * (-hh) + *x2; + ll_y -= *Ayx * (-hw) + *Ayy * (-hh) + *y2; + /* old upper right corner - new upper right corner */ + ur_x -= *Axx * hw + *Axy * hh + *x2; + ur_y -= *Ayx * hw + *Ayy * hh + *y2; + /* old lower right corner - new lower right corner */ + lr_x -= *Axx * hw + *Axy * (-hh) + *x2; + lr_y -= *Ayx * hw + *Ayy * (-hh) + *y2; + +#ifdef DEBUG_AFFINE_MAPPING + printf ("iter = %d, ul_x=%f ul_y=%f ll_x=%f ll_y=%f ur_x=%f ur_y=%f lr_x=%f lr_y=%f \n", + iteration, ul_x, ul_y, ll_x, ll_y, ur_x, ur_y, lr_x, lr_y); +#endif + + convergence = (fabs(dx) < th && fabs(dy) < th && + fabs(ul_x) < th_aff && fabs(ul_y) < th_aff && + fabs(ll_x) < th_aff && fabs(ll_y) < th_aff && + fabs(ur_x) < th_aff && fabs(ur_y) < th_aff && + fabs(lr_x) < th_aff && fabs(lr_y) < th_aff); + } + + if (status == KLT_SMALL_DET) break; + iteration++; +#ifdef DEBUG_AFFINE_MAPPING + printf ("iter = %d, x1=%f, y1=%f, x2=%f, y2=%f, Axx=%f, Ayx=%f , Axy=%f, Ayy=%f \n",iteration, x1, y1, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy); +#endif + } while ( !convergence && iteration < max_iterations); + /*} while ( (fabs(dx)>=th || fabs(dy)>=th || (affine_map && iteration < 8) ) && iteration < max_iterations); */ + _am_free_matrix(T); + _am_free_matrix(a); + + /* Check whether window is out of bounds */ + if (*x2-hw < 0.0f || nc2-(*x2+hw) < one_plus_eps || + *y2-hh < 0.0f || nr2-(*y2+hh) < one_plus_eps) + status = KLT_OOB; + + /* Check whether feature point has moved to much during iteration*/ + if ( (*x2-old_x2) > mdd || (*y2-old_y2) > mdd ) + status = KLT_OOB; + + /* Check whether residue is too large */ + if (status == KLT_TRACKED) { + if(!affine_map){ + _computeIntensityDifference(img1, img2, x1, y1, *x2, *y2, + width, height, imgdiff); + }else{ + _am_computeIntensityDifferenceAffine(img1, img2, x1, y1, *x2, *y2, *Axx, *Ayx , *Axy, *Ayy, + width, height, imgdiff); + } +#ifdef DEBUG_AFFINE_MAPPING + printf("iter = %d final_res = %f\n", iteration, _sumAbsFloatWindow(imgdiff, width, height)/(width*height)); +#endif + if (_sumAbsFloatWindow(imgdiff, width, height)/(width*height) > max_residue) + status = KLT_LARGE_RESIDUE; + } + + /* Free memory */ + free(imgdiff); free(gradx); free(grady); + +#ifdef DEBUG_AFFINE_MAPPING + printf("iter = %d status=%d\n", iteration, status); + _KLTFreeFloatImage( aff_diff_win ); +#endif + + /* Return appropriate value */ + return status; +} + +/* + * CONSISTENCY CHECK OF FEATURES BY AFFINE MAPPING (END) + **********************************************************************/ + + + +/********************************************************************* + * KLTTrackFeatures + * + * Tracks feature points from one image to the next. + */ + +void KLTTrackFeatures( + KLT_TrackingContext tc, + KLT_PixelType *img1, + KLT_PixelType *img2, + int ncols, + int nrows, + KLT_FeatureList featurelist) +{ + _KLT_FloatImage tmpimg, floatimg1, floatimg2; + _KLT_Pyramid pyramid1, pyramid1_gradx, pyramid1_grady, + pyramid2, pyramid2_gradx, pyramid2_grady; + float subsampling = (float) tc->subsampling; + float xloc, yloc, xlocout, ylocout; + int val; + int indx, r; + KLT_BOOL floatimg1_created = FALSE; + int i; + + if (KLT_verbose >= 1) { + fprintf(stderr, "(KLT) Tracking %d features in a %d by %d image... ", + KLTCountRemainingFeatures(featurelist), ncols, nrows); + fflush(stderr); + } + + /* Check window size (and correct if necessary) */ + if (tc->window_width % 2 != 1) { + tc->window_width = tc->window_width+1; + KLTWarning("Tracking context's window width must be odd. " + "Changing to %d.\n", tc->window_width); + } + if (tc->window_height % 2 != 1) { + tc->window_height = tc->window_height+1; + KLTWarning("Tracking context's window height must be odd. " + "Changing to %d.\n", tc->window_height); + } + if (tc->window_width < 3) { + tc->window_width = 3; + KLTWarning("Tracking context's window width must be at least three. \n" + "Changing to %d.\n", tc->window_width); + } + if (tc->window_height < 3) { + tc->window_height = 3; + KLTWarning("Tracking context's window height must be at least three. \n" + "Changing to %d.\n", tc->window_height); + } + + /* Create temporary image */ + tmpimg = _KLTCreateFloatImage(ncols, nrows); + + /* Process first image by converting to float, smoothing, computing */ + /* pyramid, and computing gradient pyramids */ + if (tc->sequentialMode && tc->pyramid_last != NULL) { + pyramid1 = (_KLT_Pyramid) tc->pyramid_last; + pyramid1_gradx = (_KLT_Pyramid) tc->pyramid_last_gradx; + pyramid1_grady = (_KLT_Pyramid) tc->pyramid_last_grady; + if (pyramid1->ncols[0] != ncols || pyramid1->nrows[0] != nrows) { + KLTError("(KLTTrackFeatures) Size of incoming image (%d by %d) " + "is different from size of previous image (%d by %d)\n", + ncols, nrows, pyramid1->ncols[0], pyramid1->nrows[0]); + exit(1); + } + assert(pyramid1_gradx != NULL); + assert(pyramid1_grady != NULL); + } else { + floatimg1_created = TRUE; + floatimg1 = _KLTCreateFloatImage(ncols, nrows); + _KLTToFloatImage(img1, ncols, nrows, tmpimg); + _KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg1); + pyramid1 = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); + _KLTComputePyramid(floatimg1, pyramid1, tc->pyramid_sigma_fact); + pyramid1_gradx = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); + pyramid1_grady = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); + for (i = 0 ; i < tc->nPyramidLevels ; i++) + _KLTComputeGradients(pyramid1->img[i], tc->grad_sigma, + pyramid1_gradx->img[i], + pyramid1_grady->img[i]); + } + + /* Do the same thing with second image */ + floatimg2 = _KLTCreateFloatImage(ncols, nrows); + _KLTToFloatImage(img2, ncols, nrows, tmpimg); + _KLTComputeSmoothedImage(tmpimg, _KLTComputeSmoothSigma(tc), floatimg2); + pyramid2 = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); + _KLTComputePyramid(floatimg2, pyramid2, tc->pyramid_sigma_fact); + pyramid2_gradx = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); + pyramid2_grady = _KLTCreatePyramid(ncols, nrows, (int) subsampling, tc->nPyramidLevels); + for (i = 0 ; i < tc->nPyramidLevels ; i++) + _KLTComputeGradients(pyramid2->img[i], tc->grad_sigma, + pyramid2_gradx->img[i], + pyramid2_grady->img[i]); + + /* Write internal images */ + if (tc->writeInternalImages) { + char fname[80]; + for (i = 0 ; i < tc->nPyramidLevels ; i++) { + sprintf(fname, "kltimg_tf_i%d.pgm", i); + _KLTWriteFloatImageToPGM(pyramid1->img[i], fname); + sprintf(fname, "kltimg_tf_i%d_gx.pgm", i); + _KLTWriteFloatImageToPGM(pyramid1_gradx->img[i], fname); + sprintf(fname, "kltimg_tf_i%d_gy.pgm", i); + _KLTWriteFloatImageToPGM(pyramid1_grady->img[i], fname); + sprintf(fname, "kltimg_tf_j%d.pgm", i); + _KLTWriteFloatImageToPGM(pyramid2->img[i], fname); + sprintf(fname, "kltimg_tf_j%d_gx.pgm", i); + _KLTWriteFloatImageToPGM(pyramid2_gradx->img[i], fname); + sprintf(fname, "kltimg_tf_j%d_gy.pgm", i); + _KLTWriteFloatImageToPGM(pyramid2_grady->img[i], fname); + } + } + + /* For each feature, do ... */ + for (indx = 0 ; indx < featurelist->nFeatures ; indx++) { + + /* Only track features that are not lost */ + if (featurelist->feature[indx]->val >= 0) { + + xloc = featurelist->feature[indx]->x; + yloc = featurelist->feature[indx]->y; + + /* Transform location to coarsest resolution */ + for (r = tc->nPyramidLevels - 1 ; r >= 0 ; r--) { + xloc /= subsampling; yloc /= subsampling; + } + xlocout = xloc; ylocout = yloc; + + /* Beginning with coarsest resolution, do ... */ + for (r = tc->nPyramidLevels - 1 ; r >= 0 ; r--) { + + /* Track feature at current resolution */ + xloc *= subsampling; yloc *= subsampling; + xlocout *= subsampling; ylocout *= subsampling; + + val = _trackFeature(xloc, yloc, + &xlocout, &ylocout, + pyramid1->img[r], + pyramid1_gradx->img[r], pyramid1_grady->img[r], + pyramid2->img[r], + pyramid2_gradx->img[r], pyramid2_grady->img[r], + tc->window_width, tc->window_height, + tc->step_factor, + tc->max_iterations, + tc->min_determinant, + tc->min_displacement, + tc->max_residue, + tc->lighting_insensitive); + + if (val==KLT_SMALL_DET || val==KLT_OOB) + break; + } + + /* Record feature */ + if (val == KLT_OOB) { + featurelist->feature[indx]->x = -1.0; + featurelist->feature[indx]->y = -1.0; + featurelist->feature[indx]->val = KLT_OOB; + if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); + if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); + if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); + featurelist->feature[indx]->aff_img = NULL; + featurelist->feature[indx]->aff_img_gradx = NULL; + featurelist->feature[indx]->aff_img_grady = NULL; + + } else if (_outOfBounds(xlocout, ylocout, ncols, nrows, tc->borderx, tc->bordery)) { + featurelist->feature[indx]->x = -1.0; + featurelist->feature[indx]->y = -1.0; + featurelist->feature[indx]->val = KLT_OOB; + if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); + if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); + if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); + featurelist->feature[indx]->aff_img = NULL; + featurelist->feature[indx]->aff_img_gradx = NULL; + featurelist->feature[indx]->aff_img_grady = NULL; + } else if (val == KLT_SMALL_DET) { + featurelist->feature[indx]->x = -1.0; + featurelist->feature[indx]->y = -1.0; + featurelist->feature[indx]->val = KLT_SMALL_DET; + if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); + if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); + if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); + featurelist->feature[indx]->aff_img = NULL; + featurelist->feature[indx]->aff_img_gradx = NULL; + featurelist->feature[indx]->aff_img_grady = NULL; + } else if (val == KLT_LARGE_RESIDUE) { + featurelist->feature[indx]->x = -1.0; + featurelist->feature[indx]->y = -1.0; + featurelist->feature[indx]->val = KLT_LARGE_RESIDUE; + if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); + if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); + if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); + featurelist->feature[indx]->aff_img = NULL; + featurelist->feature[indx]->aff_img_gradx = NULL; + featurelist->feature[indx]->aff_img_grady = NULL; + } else if (val == KLT_MAX_ITERATIONS) { + featurelist->feature[indx]->x = -1.0; + featurelist->feature[indx]->y = -1.0; + featurelist->feature[indx]->val = KLT_MAX_ITERATIONS; + if( featurelist->feature[indx]->aff_img ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); + if( featurelist->feature[indx]->aff_img_gradx ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); + if( featurelist->feature[indx]->aff_img_grady ) _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); + featurelist->feature[indx]->aff_img = NULL; + featurelist->feature[indx]->aff_img_gradx = NULL; + featurelist->feature[indx]->aff_img_grady = NULL; + } else { + featurelist->feature[indx]->x = xlocout; + featurelist->feature[indx]->y = ylocout; + featurelist->feature[indx]->val = KLT_TRACKED; + if (tc->affineConsistencyCheck >= 0 && val == KLT_TRACKED) { /*for affine mapping*/ + int border = 2; /* add border for interpolation */ + +#ifdef DEBUG_AFFINE_MAPPING + glob_index = indx; +#endif + + if(!featurelist->feature[indx]->aff_img){ + /* save image and gradient for each feature at finest resolution after first successful track */ + featurelist->feature[indx]->aff_img = _KLTCreateFloatImage((tc->affine_window_width+border), (tc->affine_window_height+border)); + featurelist->feature[indx]->aff_img_gradx = _KLTCreateFloatImage((tc->affine_window_width+border), (tc->affine_window_height+border)); + featurelist->feature[indx]->aff_img_grady = _KLTCreateFloatImage((tc->affine_window_width+border), (tc->affine_window_height+border)); + _am_getSubFloatImage(pyramid1->img[0],xloc,yloc,featurelist->feature[indx]->aff_img); + _am_getSubFloatImage(pyramid1_gradx->img[0],xloc,yloc,featurelist->feature[indx]->aff_img_gradx); + _am_getSubFloatImage(pyramid1_grady->img[0],xloc,yloc,featurelist->feature[indx]->aff_img_grady); + featurelist->feature[indx]->aff_x = xloc - (int) xloc + (tc->affine_window_width+border)/2; + featurelist->feature[indx]->aff_y = yloc - (int) yloc + (tc->affine_window_height+border)/2;; + }else{ + /* affine tracking */ + val = _am_trackFeatureAffine(featurelist->feature[indx]->aff_x, featurelist->feature[indx]->aff_y, + &xlocout, &ylocout, + featurelist->feature[indx]->aff_img, + featurelist->feature[indx]->aff_img_gradx, + featurelist->feature[indx]->aff_img_grady, + pyramid2->img[0], + pyramid2_gradx->img[0], pyramid2_grady->img[0], + tc->affine_window_width, tc->affine_window_height, + tc->step_factor, + tc->affine_max_iterations, + tc->min_determinant, + tc->min_displacement, + tc->affine_min_displacement, + tc->affine_max_residue, + tc->lighting_insensitive, + tc->affineConsistencyCheck, + tc->affine_max_displacement_differ, + &featurelist->feature[indx]->aff_Axx, + &featurelist->feature[indx]->aff_Ayx, + &featurelist->feature[indx]->aff_Axy, + &featurelist->feature[indx]->aff_Ayy + ); + featurelist->feature[indx]->val = val; + if(val != KLT_TRACKED){ + featurelist->feature[indx]->x = -1.0; + featurelist->feature[indx]->y = -1.0; + featurelist->feature[indx]->aff_x = -1.0; + featurelist->feature[indx]->aff_y = -1.0; + /* free image and gradient for lost feature */ + _KLTFreeFloatImage(featurelist->feature[indx]->aff_img); + _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_gradx); + _KLTFreeFloatImage(featurelist->feature[indx]->aff_img_grady); + featurelist->feature[indx]->aff_img = NULL; + featurelist->feature[indx]->aff_img_gradx = NULL; + featurelist->feature[indx]->aff_img_grady = NULL; + }else{ + /*featurelist->feature[indx]->x = xlocout;*/ + /*featurelist->feature[indx]->y = ylocout;*/ + } + } + } + + } + } + } + + if (tc->sequentialMode) { + tc->pyramid_last = pyramid2; + tc->pyramid_last_gradx = pyramid2_gradx; + tc->pyramid_last_grady = pyramid2_grady; + } else { + _KLTFreePyramid(pyramid2); + _KLTFreePyramid(pyramid2_gradx); + _KLTFreePyramid(pyramid2_grady); + } + + /* Free memory */ + _KLTFreeFloatImage(tmpimg); + if (floatimg1_created) _KLTFreeFloatImage(floatimg1); + _KLTFreeFloatImage(floatimg2); + _KLTFreePyramid(pyramid1); + _KLTFreePyramid(pyramid1_gradx); + _KLTFreePyramid(pyramid1_grady); + + if (KLT_verbose >= 1) { + fprintf(stderr, "\n\t%d features successfully tracked.\n", + KLTCountRemainingFeatures(featurelist)); + if (tc->writeInternalImages) + fprintf(stderr, "\tWrote images to 'kltimg_tf*.pgm'.\n"); + fflush(stderr); + } + +} + + diff --git a/rtengine/lcp.cc b/rtengine/lcp.cc index 51e19d7f0..e699fd47d 100644 --- a/rtengine/lcp.cc +++ b/rtengine/lcp.cc @@ -1,681 +1,681 @@ -/* -* This file is part of RawTherapee. -* -* Copyright (c) 2012 Oliver Duis -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -*/ -#include - -#include "lcp.h" -#include "safegtk.h" -#include "iccmatrices.h" -#include "iccstore.h" -#include "rawimagesource.h" -#include "improcfun.h" -#include "rt_math.h" - -#ifdef WIN32 -#include -// for GCC32 -#ifndef _WIN32_IE -#define _WIN32_IE 0x0600 -#endif -#include -#endif - - -using namespace std; -using namespace rtengine; -using namespace rtexif; - - -LCPModelCommon::LCPModelCommon() { - focLenX=focLenY=-1; imgXCenter=imgYCenter=0.5; - x0=y0=fx=fy=meanErr=0; badErr=false; - for (int i=0;i<5;i++) param[i]=0; - scaleFac=1; -} - -bool LCPModelCommon::empty() const { - return param[0]==0 && param[1]==0 && param[2]==0; -} - -void LCPModelCommon::print() const { - printf("focLen %g/%g; imgCenter %g/%g; scale %g; err %g\n",focLenX,focLenY,imgXCenter,imgYCenter,scaleFac,meanErr); - printf("xy0 %g/%g fxy %g/%g\n",x0,y0,fx,fy); - printf("param: %g/%g/%g/%g/%g\n",param[0],param[1],param[2],param[3],param[4]); -} - -// weightened merge two parameters -void LCPModelCommon::merge(const LCPModelCommon& a, const LCPModelCommon& b, float facA) { - float facB=1-facA; - - focLenX = facA * a.focLenX + facB * b.focLenX; - focLenY = facA * a.focLenY + facB * b.focLenY; - imgXCenter = facA * a.imgXCenter + facB * b.imgXCenter; - imgYCenter = facA * a.imgYCenter + facB * b.imgYCenter; - scaleFac = facA * a.scaleFac + facB * b.scaleFac; - meanErr = facA * a.meanErr + facB * b.meanErr; - - for (int i=0;i<5;i++) param[i]= facA * a.param[i] + facB * b.param[i]; -} - -void LCPModelCommon::prepareParams(int fullWidth, int fullHeight, float focalLength, float focalLength35mm, float sensorFormatFactor, bool swapXY, bool mirrorX, bool mirrorY) { - // Mention that the Adobe technical paper has a bug here, the DMAX is handled differently for focLen and imgCenter - int Dmax=fullWidth; if (fullHeight>fullWidth) Dmax=fullHeight; - - // correct focLens - if (focLenX<0) { // they may not be given - // and 35mm may not be given either - if (focalLength35mm<1) focalLength35mm = focalLength*sensorFormatFactor; - - focLenX=focLenY=focalLength / ( 35*focalLength/focalLength35mm); // focLen must be calculated in pixels - } - - if (swapXY) { - x0 = (mirrorX ? 1.-imgYCenter : imgYCenter) * fullWidth; - y0 = (mirrorY ? 1.-imgXCenter : imgXCenter) * fullHeight; - fx = focLenY * Dmax; - fy = focLenX * Dmax; - } else { - x0 = (mirrorX ? 1.-imgXCenter : imgXCenter) * fullWidth; - y0 = (mirrorY ? 1.-imgYCenter : imgYCenter) * fullHeight; - fx = focLenX * Dmax; - fy = focLenY * Dmax; - } - //printf("FW %i /X0 %g FH %i /Y0 %g %g\n",fullWidth,x0,fullHeight,y0, imgYCenter); -} - -LCPPersModel::LCPPersModel() { - focLen=focDist=aperture=0; -} - -// mode: 0=distortion, 1=vignette, 2=CA -bool LCPPersModel::hasModeData(int mode) const { - return (mode==0 && !vignette.empty() && !vignette.badErr) || (mode==1 && !base.empty() && !base.badErr) - || (mode==2 && !chromRG.empty() && !chromG.empty() && !chromBG.empty() && - !chromRG.badErr && !chromG.badErr && !chromBG.badErr); -} - -void LCPPersModel::print() const { - printf("--- PersModel focLen %g; focDist %g; aperture %g\n", focLen, focDist, aperture); - printf("Base:\n"); base.print(); - if (!chromRG.empty()) { printf("ChromRG:\n"); chromRG.print(); } - if (!chromG.empty()) { printf("ChromG:\n"); chromG.print(); } - if (!chromBG.empty()) { printf("ChromBG:\n"); chromBG.print(); } - if (!vignette.empty()) { printf("Vignette:\n"); vignette.print(); } - printf("\n"); -} - -// if !vignette then geometric and CA -LCPMapper::LCPMapper(LCPProfile* pProf, float focalLength, float focalLength35mm, float focusDist, float aperture, bool vignette, bool useCADistP, - int fullWidth, int fullHeight, const CoarseTransformParams& coarse, int rawRotationDeg) -{ - if (pProf==NULL) return; - - useCADist=useCADistP; - - // determine in what the image with the RAW landscape in comparison (calibration target) - // in vignetting, the rotation has not taken place yet - int rot = 0; - if (rawRotationDeg>=0) rot=(coarse.rotate+rawRotationDeg) % 360; - - swapXY = (rot==90 || rot==270); - bool mirrorX = (rot==90 || rot==180); - bool mirrorY = (rot==180 || rot==270); - //printf("Vign: %i, fullWidth: %i/%i, focLen %g SwapXY: %i / MirX/Y %i / %i on rot:%i from %i\n",vignette, fullWidth, fullHeight, focalLength, swapXY, mirrorX, mirrorY, rot, rawRotationDeg); - - pProf->calcParams(vignette?0:1, focalLength, focusDist, aperture, &mc, NULL, NULL); - mc.prepareParams(fullWidth, fullHeight, focalLength, focalLength35mm, pProf->sensorFormatFactor, swapXY, mirrorX, mirrorY); - - if (!vignette) { - pProf->calcParams(2, focalLength, focusDist, aperture, &chrom[0], &chrom[1], &chrom[2]); - for (int i=0;i<3;i++) chrom[i].prepareParams(fullWidth, fullHeight, focalLength, focalLength35mm, pProf->sensorFormatFactor, swapXY, mirrorX, mirrorY); - } - - enableCA = !vignette && focusDist>0; -} - -void LCPMapper::correctDistortion(double& x, double& y) const { - double xd=(x-mc.x0)/mc.fx, yd=(y-mc.y0)/mc.fy; - - const float* aDist = mc.param; - double rsqr = xd*xd+yd*yd; - double xfac=aDist[swapXY?3:4], yfac=aDist[swapXY?4:3]; - - double commonFac = (((aDist[2]*rsqr + aDist[1])*rsqr + aDist[0])*rsqr + 1.) - + 2. * (yfac * yd + xfac * xd); - - double xnew = xd * commonFac + xfac * rsqr; - double ynew = yd * commonFac + yfac * rsqr; - - x = xnew * mc.fx + mc.x0; - y = ynew * mc.fy + mc.y0; -} - -void LCPMapper::correctCA(double& x, double& y, int channel) const { - if (!enableCA) return; - - double rsqr, xgreen, ygreen; - - // First calc the green channel like normal distortion - // the other are just deviations from it - double xd=(x-chrom[1].x0)/chrom[1].fx, yd=(y-chrom[1].y0)/chrom[1].fy; - - // Green contains main distortion, just like base - if (useCADist) { - const float* aDist = chrom[1].param; - double rsqr = xd*xd+yd*yd; - double xfac=aDist[swapXY?3:4], yfac=aDist[swapXY?4:3]; - - double commonFac = (((aDist[2]*rsqr + aDist[1])*rsqr + aDist[0])*rsqr + 1.) - + 2. * (yfac * yd + xfac * xd); - - xgreen = xd * commonFac + aDist[4] * rsqr; - ygreen = yd * commonFac + aDist[3] * rsqr; - } else { - xgreen=xd; ygreen=yd; - } - - if (channel==1) { - // green goes directly - x = xgreen * chrom[1].fx + chrom[1].x0; - y = ygreen * chrom[1].fy + chrom[1].y0; - } else { - // others are diffs from green - xd=xgreen; yd=ygreen; - rsqr=xd*xd+yd*yd; - - const float* aCA =chrom[channel].param; - double xfac=aCA[swapXY?3:4], yfac=aCA[swapXY?4:3]; - double commonSum = 1. + rsqr * (aCA[0] + rsqr * (aCA[1] + aCA[2]*rsqr)) + 2. * (yfac*yd + xfac*xd); - - x = (chrom[channel].scaleFac * ( xd * commonSum + xfac*rsqr )) * chrom[channel].fx + chrom[channel].x0; - y = (chrom[channel].scaleFac * ( yd * commonSum + yfac*rsqr )) * chrom[channel].fy + chrom[channel].y0; - } -} - -float LCPMapper::calcVignetteFac(int x, int y) const { - // No need for swapXY, since vignette is in RAW and always before rotation - double xd=((double)x-mc.x0)/mc.fx, yd=((double)y-mc.y0)/mc.fy; - - const float* aVig= mc.param; - double rsqr = xd*xd+yd*yd; - double param0Sqr = aVig[0]*aVig[0]; - - return 1. + rsqr * (-aVig[0] + rsqr * ((param0Sqr - aVig[1]) - - (param0Sqr*aVig[0] - 2.*aVig[0]*aVig[1] + aVig[2]) *rsqr - + (param0Sqr*param0Sqr + aVig[1]*aVig[1] - + 2.*aVig[0]*aVig[2] - 3.*param0Sqr*aVig[1]) *rsqr*rsqr)); -} - -LCPProfile::LCPProfile(Glib::ustring fname) { - const int BufferSize=8192; - char buf[BufferSize]; - - XML_Parser parser = XML_ParserCreate(NULL); - if (!parser) throw "Couldn't allocate memory for XML parser"; - - XML_SetElementHandler(parser, XmlStartHandler, XmlEndHandler); - XML_SetCharacterDataHandler(parser, XmlTextHandler); - XML_SetUserData(parser, (void *)this); - - - isFisheye=inCamProfiles=firstLIDone=inPerspect=inAlternateLensID=inAlternateLensNames=false; - sensorFormatFactor=1; - for (int i=0;ihasModeData(0)) { - errVignette+=aPersModel[pm]->vignette.meanErr; - vignetteCount++; - } - - if (aPersModel[pm]->hasModeData(1)) { - errBase+=aPersModel[pm]->base.meanErr; - baseCount++; - } - - if (aPersModel[pm]->hasModeData(2)) { - errChrom+=std::max(std::max(aPersModel[pm]->chromRG.meanErr,aPersModel[pm]->chromG.meanErr),aPersModel[pm]->chromBG.meanErr); - chromCount++; - } - } - - // Only if we have enough frames, filter out errors - int filtered=0; - - if (baseCount+chromCount+vignetteCount>=minFramesLeft) { - if (baseCount>0) errBase/=(double)baseCount; - if (chromCount>0) errChrom/=(double)chromCount; - if (vignetteCount>0) errVignette/=(double)vignetteCount; - - // Now mark all the bad ones as bad, and hasModeData will return false; - for (int pm=0;pmhasModeData(0) && aPersModel[pm]->vignette.meanErr > maxAvgDevFac * errVignette) { - aPersModel[pm]->vignette.badErr=true; - filtered++; - } - - if (aPersModel[pm]->hasModeData(1) && aPersModel[pm]->base.meanErr > maxAvgDevFac * errBase) { - aPersModel[pm]->base.badErr=true; - filtered++; - } - - if (aPersModel[pm]->hasModeData(2) && - (aPersModel[pm]->chromRG.meanErr > maxAvgDevFac * errChrom || aPersModel[pm]->chromG.meanErr > maxAvgDevFac * errChrom - || aPersModel[pm]->chromBG.meanErr > maxAvgDevFac * errChrom)) { - aPersModel[pm]->chromRG.badErr=aPersModel[pm]->chromG.badErr=aPersModel[pm]->chromBG.badErr=true; - filtered++; - } - } - - //printf("Filtered %.1f%% frames for maxAvgDevFac %g leaving %i\n", filtered*100./(baseCount+chromCount+vignetteCount), maxAvgDevFac, baseCount+chromCount+vignetteCount-filtered); - } - - return filtered; -} - - -// mode: 0=vignette, 1=distortion, 2=CA -void LCPProfile::calcParams(int mode, float focalLength, float focusDist, float aperture, LCPModelCommon *pCorr1, LCPModelCommon *pCorr2, LCPModelCommon *pCorr3) const { - float euler=exp(1.0); - - // find the frames with the least distance, focal length wise - LCPPersModel *pLow=NULL, *pHigh=NULL; +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2012 Oliver Duis +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ +#include - float focalLengthLog=log(focalLength); //, apertureLog=aperture>0 ? log(aperture) : 0; - float focusDistLog=focusDist>0? log(focusDist)+euler : 0; - - // Pass 1: determining best focal length, if possible different focusDistances (for the focDist is not given case) - for (int pm=0;pmfocLen; - - if (aPersModel[pm]->hasModeData(mode)) { - if (f <= focalLength && (pLow==NULL || f > pLow->focLen || (focusDist==0 && f==pLow->focLen && pLow->focDist>aPersModel[pm]->focDist))) { - pLow=aPersModel[pm]; - } - if (f >= focalLength && (pHigh==NULL || f < pHigh->focLen || (focusDist==0 && f==pHigh->focLen && pHigh->focDistfocDist))) { - pHigh=aPersModel[pm]; - } - } - } - - if (!pLow) - pLow=pHigh; - else if (!pHigh) - pHigh=pLow; - else { - // Pass 2: We have some, so take the best aperture for vignette and best focus for CA and distortion - // there are usually several frame per focal length. In the end pLow will have both flen and apterure/focdis below the target, - // and vice versa pHigh - float bestFocLenLow=pLow->focLen, bestFocLenHigh=pHigh->focLen; - - for (int pm=0;pmaperture; // float aperLog=log(aper); - float focDist=aPersModel[pm]->focDist; float focDistLog=log(focDist)+euler; - double meanErr; - - if (aPersModel[pm]->hasModeData(mode)) { - if (mode==0) { - meanErr=aPersModel[pm]->vignette.meanErr; - - // by aperture (vignette), and max out focus distance - // tests showed doing this by log(aperture) is not as advisable - if (aPersModel[pm]->focLen==bestFocLenLow && ( - (aper==aperture && pLow->vignette.meanErr>meanErr) - || (aper>=aperture && aperaperture && pLow->aperture > aperture) - || (aper<=aperture && (pLow->aperture>aperture || fabs(aperture-aper)aperture))))) { - pLow=aPersModel[pm]; - } - if (aPersModel[pm]->focLen==bestFocLenHigh && ( - (aper==aperture && pHigh->vignette.meanErr>meanErr) - || (aper<=aperture && aper>pHigh->aperture && pHigh->aperture < aperture) - || (aper>=aperture && (pHigh->apertureaperture))))) { - pHigh=aPersModel[pm]; - } - } else { - meanErr = (mode==1 ? aPersModel[pm]->base.meanErr : aPersModel[pm]->chromG.meanErr); - - if (focusDist>0) { - // by focus distance - if (aPersModel[pm]->focLen==bestFocLenLow && ( - (focDist==focusDist && (mode==1 ? pLow->base.meanErr : pLow->chromG.meanErr)>meanErr) - || (focDist>=focusDist && focDistfocDist && pLow->focDist > focusDist) - || (focDist<=focusDist && (pLow->focDist>focusDist || fabs(focusDistLog-focDistLog)focDist)+euler)))))) { - pLow=aPersModel[pm]; - } - if (aPersModel[pm]->focLen==bestFocLenHigh && ( - (focDist==focusDist && (mode==1 ? pHigh->base.meanErr : pHigh->chromG.meanErr)>meanErr) - || (focDist<=focusDist && focDist>pHigh->focDist && pHigh->focDist < focusDist) - || (focDist>=focusDist && (pHigh->focDistfocDist)+euler)))))) { - pHigh=aPersModel[pm]; - } - } else { - // no focus distance available, just error - if (aPersModel[pm]->focLen==bestFocLenLow && (mode==1 ? pLow->base.meanErr : pLow->chromG.meanErr)>meanErr) { - pLow=aPersModel[pm]; - } - if (aPersModel[pm]->focLen==bestFocLenHigh && (mode==1 ? pHigh->base.meanErr : pHigh->chromG.meanErr)>meanErr) { - pHigh=aPersModel[pm]; - } - } - } - } - } - } - - if (pLow!=NULL && pHigh!=NULL) { - // average out the factors, linear interpolation in logarithmic scale - float facLow=0.5; - bool focLenOnSpot=false; // pretty often, since max/min are often as frames in LCP - - // There is as foclen range, take that as basis - if (pLow->focLen < pHigh->focLen) { - facLow = (log(pHigh->focLen)-focalLengthLog) / (log(pHigh->focLen) - log(pLow->focLen)); - } else { - focLenOnSpot=pLow->focLen==pHigh->focLen && pLow->focLen==focalLength; - } - - // and average the other factor if available - if (mode==0 && pLow->aperture < aperture && pHigh->aperture > aperture) { - // Mix in aperture - float facAperLow = (pHigh->aperture - aperture) / (pHigh->aperture - pLow->aperture); - facLow = focLenOnSpot ? facAperLow : (0.5*facLow + 0.5*facAperLow); - } else if (mode!=0 && focusDist>0 && pLow->focDist < focusDist && pHigh->focDist > focusDist) { - // focus distance for all else (if focus distance is given) - float facDistLow = (log(pHigh->focDist)+euler - focusDistLog) / (log(pHigh->focDist) - log(pLow->focDist)); - facLow = focLenOnSpot ? facDistLow : (0.8*facLow + 0.2*facDistLow); - } - - switch (mode) { - case 0: // vignette - pCorr1->merge(pLow->vignette, pHigh->vignette, facLow); - break; - - case 1: // distortion - pCorr1->merge(pLow->base, pHigh->base, facLow); - break; - - case 2: // CA - pCorr1->merge(pLow->chromRG, pHigh->chromRG, facLow); - pCorr2->merge(pLow->chromG, pHigh->chromG, facLow); - pCorr3->merge(pLow->chromBG, pHigh->chromBG, facLow); - break; - } - - //printf("LCP mode=%i, dist: %g found frames: Fno %g-%g; FocLen %g-%g; Dist %g-%g with weight %g\n", mode, focusDist, pLow->aperture, pHigh->aperture, pLow->focLen, pHigh->focLen, pLow->focDist, pHigh->focDist, facLow); - } else printf("Error: LCP file contained no %s parameters\n",mode==0 ? "vignette" : mode == 1 ? "distortion" : "CA" ); -} - -void LCPProfile::print() const { - printf("=== Profile %s\n", profileName.c_str()); - printf("Frames: %i, RAW: %i; Fisheye: %i; Sensorformat: %f\n",persModelCount,isRaw,isFisheye,sensorFormatFactor); - for (int pm=0;pmprint(); -} - -void XMLCALL LCPProfile::XmlStartHandler(void *pLCPProfile, const char *el, const char **attr) { - LCPProfile *pProf=static_cast(pLCPProfile); - bool parseAttr=false; - - if (*pProf->inInvalidTag) return; // We ignore everything in dirty tag till it's gone - - // clean up tagname - const char* src=strrchr(el,':'); - if (src==NULL) src=const_cast(el); else src++; - - strcpy(pProf->lastTag,src); - - if (!strcmp("VignetteModelPiecewiseParam",src)) strcpy(pProf->inInvalidTag,src); - - if (!strcmp("CameraProfiles",src)) pProf->inCamProfiles=true; - if (!strcmp("AlternateLensIDs",src)) pProf->inAlternateLensID=true; - if (!strcmp("AlternateLensNames",src)) pProf->inAlternateLensNames=true; - if (!pProf->inCamProfiles || pProf->inAlternateLensID || pProf->inAlternateLensNames) return; - - if (!strcmp("li",src)) { - pProf->pCurPersModel=new LCPPersModel(); - pProf->pCurCommon=&pProf->pCurPersModel->base; // iterated to next tags within persModel - return; - } - - if (!strcmp("PerspectiveModel",src)) { - pProf->firstLIDone=true; pProf->inPerspect=true; - return; - } else if (!strcmp("FisheyeModel",src)) { - pProf->firstLIDone=true; pProf->inPerspect=true; - pProf->isFisheye=true; // just misses third param, and different path, rest is the same - return; - } else if (!strcmp("Description",src)) parseAttr=true; - - // Move pointer to general section - if (pProf->inPerspect) { - if (!strcmp("ChromaticRedGreenModel",src)) { - pProf->pCurCommon=&pProf->pCurPersModel->chromRG; - parseAttr=true; - } else if (!strcmp("ChromaticGreenModel",src)) { - pProf->pCurCommon=&pProf->pCurPersModel->chromG; - parseAttr=true; - } else if (!strcmp("ChromaticBlueGreenModel",src)) { - pProf->pCurCommon=&pProf->pCurPersModel->chromBG; - parseAttr=true; +#include "lcp.h" +#include "safegtk.h" +#include "iccmatrices.h" +#include "iccstore.h" +#include "rawimagesource.h" +#include "improcfun.h" +#include "rt_math.h" + +#ifdef WIN32 +#include +// for GCC32 +#ifndef _WIN32_IE +#define _WIN32_IE 0x0600 +#endif +#include +#endif + + +using namespace std; +using namespace rtengine; +using namespace rtexif; + + +LCPModelCommon::LCPModelCommon() { + focLenX=focLenY=-1; imgXCenter=imgYCenter=0.5; + x0=y0=fx=fy=meanErr=0; badErr=false; + for (int i=0;i<5;i++) param[i]=0; + scaleFac=1; +} + +bool LCPModelCommon::empty() const { + return param[0]==0 && param[1]==0 && param[2]==0; +} + +void LCPModelCommon::print() const { + printf("focLen %g/%g; imgCenter %g/%g; scale %g; err %g\n",focLenX,focLenY,imgXCenter,imgYCenter,scaleFac,meanErr); + printf("xy0 %g/%g fxy %g/%g\n",x0,y0,fx,fy); + printf("param: %g/%g/%g/%g/%g\n",param[0],param[1],param[2],param[3],param[4]); +} + +// weightened merge two parameters +void LCPModelCommon::merge(const LCPModelCommon& a, const LCPModelCommon& b, float facA) { + float facB=1-facA; + + focLenX = facA * a.focLenX + facB * b.focLenX; + focLenY = facA * a.focLenY + facB * b.focLenY; + imgXCenter = facA * a.imgXCenter + facB * b.imgXCenter; + imgYCenter = facA * a.imgYCenter + facB * b.imgYCenter; + scaleFac = facA * a.scaleFac + facB * b.scaleFac; + meanErr = facA * a.meanErr + facB * b.meanErr; + + for (int i=0;i<5;i++) param[i]= facA * a.param[i] + facB * b.param[i]; +} + +void LCPModelCommon::prepareParams(int fullWidth, int fullHeight, float focalLength, float focalLength35mm, float sensorFormatFactor, bool swapXY, bool mirrorX, bool mirrorY) { + // Mention that the Adobe technical paper has a bug here, the DMAX is handled differently for focLen and imgCenter + int Dmax=fullWidth; if (fullHeight>fullWidth) Dmax=fullHeight; + + // correct focLens + if (focLenX<0) { // they may not be given + // and 35mm may not be given either + if (focalLength35mm<1) focalLength35mm = focalLength*sensorFormatFactor; + + focLenX=focLenY=focalLength / ( 35*focalLength/focalLength35mm); // focLen must be calculated in pixels + } + + if (swapXY) { + x0 = (mirrorX ? 1.-imgYCenter : imgYCenter) * fullWidth; + y0 = (mirrorY ? 1.-imgXCenter : imgXCenter) * fullHeight; + fx = focLenY * Dmax; + fy = focLenX * Dmax; + } else { + x0 = (mirrorX ? 1.-imgXCenter : imgXCenter) * fullWidth; + y0 = (mirrorY ? 1.-imgYCenter : imgYCenter) * fullHeight; + fx = focLenX * Dmax; + fy = focLenY * Dmax; + } + //printf("FW %i /X0 %g FH %i /Y0 %g %g\n",fullWidth,x0,fullHeight,y0, imgYCenter); +} + +LCPPersModel::LCPPersModel() { + focLen=focDist=aperture=0; +} + +// mode: 0=distortion, 1=vignette, 2=CA +bool LCPPersModel::hasModeData(int mode) const { + return (mode==0 && !vignette.empty() && !vignette.badErr) || (mode==1 && !base.empty() && !base.badErr) + || (mode==2 && !chromRG.empty() && !chromG.empty() && !chromBG.empty() && + !chromRG.badErr && !chromG.badErr && !chromBG.badErr); +} + +void LCPPersModel::print() const { + printf("--- PersModel focLen %g; focDist %g; aperture %g\n", focLen, focDist, aperture); + printf("Base:\n"); base.print(); + if (!chromRG.empty()) { printf("ChromRG:\n"); chromRG.print(); } + if (!chromG.empty()) { printf("ChromG:\n"); chromG.print(); } + if (!chromBG.empty()) { printf("ChromBG:\n"); chromBG.print(); } + if (!vignette.empty()) { printf("Vignette:\n"); vignette.print(); } + printf("\n"); +} + +// if !vignette then geometric and CA +LCPMapper::LCPMapper(LCPProfile* pProf, float focalLength, float focalLength35mm, float focusDist, float aperture, bool vignette, bool useCADistP, + int fullWidth, int fullHeight, const CoarseTransformParams& coarse, int rawRotationDeg) +{ + if (pProf==NULL) return; + + useCADist=useCADistP; + + // determine in what the image with the RAW landscape in comparison (calibration target) + // in vignetting, the rotation has not taken place yet + int rot = 0; + if (rawRotationDeg>=0) rot=(coarse.rotate+rawRotationDeg) % 360; + + swapXY = (rot==90 || rot==270); + bool mirrorX = (rot==90 || rot==180); + bool mirrorY = (rot==180 || rot==270); + //printf("Vign: %i, fullWidth: %i/%i, focLen %g SwapXY: %i / MirX/Y %i / %i on rot:%i from %i\n",vignette, fullWidth, fullHeight, focalLength, swapXY, mirrorX, mirrorY, rot, rawRotationDeg); + + pProf->calcParams(vignette?0:1, focalLength, focusDist, aperture, &mc, NULL, NULL); + mc.prepareParams(fullWidth, fullHeight, focalLength, focalLength35mm, pProf->sensorFormatFactor, swapXY, mirrorX, mirrorY); + + if (!vignette) { + pProf->calcParams(2, focalLength, focusDist, aperture, &chrom[0], &chrom[1], &chrom[2]); + for (int i=0;i<3;i++) chrom[i].prepareParams(fullWidth, fullHeight, focalLength, focalLength35mm, pProf->sensorFormatFactor, swapXY, mirrorX, mirrorY); + } + + enableCA = !vignette && focusDist>0; +} + +void LCPMapper::correctDistortion(double& x, double& y) const { + double xd=(x-mc.x0)/mc.fx, yd=(y-mc.y0)/mc.fy; + + const float* aDist = mc.param; + double rsqr = xd*xd+yd*yd; + double xfac=aDist[swapXY?3:4], yfac=aDist[swapXY?4:3]; + + double commonFac = (((aDist[2]*rsqr + aDist[1])*rsqr + aDist[0])*rsqr + 1.) + + 2. * (yfac * yd + xfac * xd); + + double xnew = xd * commonFac + xfac * rsqr; + double ynew = yd * commonFac + yfac * rsqr; + + x = xnew * mc.fx + mc.x0; + y = ynew * mc.fy + mc.y0; +} + +void LCPMapper::correctCA(double& x, double& y, int channel) const { + if (!enableCA) return; + + double rsqr, xgreen, ygreen; + + // First calc the green channel like normal distortion + // the other are just deviations from it + double xd=(x-chrom[1].x0)/chrom[1].fx, yd=(y-chrom[1].y0)/chrom[1].fy; + + // Green contains main distortion, just like base + if (useCADist) { + const float* aDist = chrom[1].param; + double rsqr = xd*xd+yd*yd; + double xfac=aDist[swapXY?3:4], yfac=aDist[swapXY?4:3]; + + double commonFac = (((aDist[2]*rsqr + aDist[1])*rsqr + aDist[0])*rsqr + 1.) + + 2. * (yfac * yd + xfac * xd); + + xgreen = xd * commonFac + aDist[4] * rsqr; + ygreen = yd * commonFac + aDist[3] * rsqr; + } else { + xgreen=xd; ygreen=yd; + } + + if (channel==1) { + // green goes directly + x = xgreen * chrom[1].fx + chrom[1].x0; + y = ygreen * chrom[1].fy + chrom[1].y0; + } else { + // others are diffs from green + xd=xgreen; yd=ygreen; + rsqr=xd*xd+yd*yd; + + const float* aCA =chrom[channel].param; + double xfac=aCA[swapXY?3:4], yfac=aCA[swapXY?4:3]; + double commonSum = 1. + rsqr * (aCA[0] + rsqr * (aCA[1] + aCA[2]*rsqr)) + 2. * (yfac*yd + xfac*xd); + + x = (chrom[channel].scaleFac * ( xd * commonSum + xfac*rsqr )) * chrom[channel].fx + chrom[channel].x0; + y = (chrom[channel].scaleFac * ( yd * commonSum + yfac*rsqr )) * chrom[channel].fy + chrom[channel].y0; + } +} + +float LCPMapper::calcVignetteFac(int x, int y) const { + // No need for swapXY, since vignette is in RAW and always before rotation + double xd=((double)x-mc.x0)/mc.fx, yd=((double)y-mc.y0)/mc.fy; + + const float* aVig= mc.param; + double rsqr = xd*xd+yd*yd; + double param0Sqr = aVig[0]*aVig[0]; + + return 1. + rsqr * (-aVig[0] + rsqr * ((param0Sqr - aVig[1]) + - (param0Sqr*aVig[0] - 2.*aVig[0]*aVig[1] + aVig[2]) *rsqr + + (param0Sqr*param0Sqr + aVig[1]*aVig[1] + + 2.*aVig[0]*aVig[2] - 3.*param0Sqr*aVig[1]) *rsqr*rsqr)); +} + +LCPProfile::LCPProfile(Glib::ustring fname) { + const int BufferSize=8192; + char buf[BufferSize]; + + XML_Parser parser = XML_ParserCreate(NULL); + if (!parser) throw "Couldn't allocate memory for XML parser"; + + XML_SetElementHandler(parser, XmlStartHandler, XmlEndHandler); + XML_SetCharacterDataHandler(parser, XmlTextHandler); + XML_SetUserData(parser, (void *)this); + + + isFisheye=inCamProfiles=firstLIDone=inPerspect=inAlternateLensID=inAlternateLensNames=false; + sensorFormatFactor=1; + for (int i=0;ihasModeData(0)) { + errVignette+=aPersModel[pm]->vignette.meanErr; + vignetteCount++; + } + + if (aPersModel[pm]->hasModeData(1)) { + errBase+=aPersModel[pm]->base.meanErr; + baseCount++; + } + + if (aPersModel[pm]->hasModeData(2)) { + errChrom+=std::max(std::max(aPersModel[pm]->chromRG.meanErr,aPersModel[pm]->chromG.meanErr),aPersModel[pm]->chromBG.meanErr); + chromCount++; + } + } + + // Only if we have enough frames, filter out errors + int filtered=0; + + if (baseCount+chromCount+vignetteCount>=minFramesLeft) { + if (baseCount>0) errBase/=(double)baseCount; + if (chromCount>0) errChrom/=(double)chromCount; + if (vignetteCount>0) errVignette/=(double)vignetteCount; + + // Now mark all the bad ones as bad, and hasModeData will return false; + for (int pm=0;pmhasModeData(0) && aPersModel[pm]->vignette.meanErr > maxAvgDevFac * errVignette) { + aPersModel[pm]->vignette.badErr=true; + filtered++; + } + + if (aPersModel[pm]->hasModeData(1) && aPersModel[pm]->base.meanErr > maxAvgDevFac * errBase) { + aPersModel[pm]->base.badErr=true; + filtered++; + } + + if (aPersModel[pm]->hasModeData(2) && + (aPersModel[pm]->chromRG.meanErr > maxAvgDevFac * errChrom || aPersModel[pm]->chromG.meanErr > maxAvgDevFac * errChrom + || aPersModel[pm]->chromBG.meanErr > maxAvgDevFac * errChrom)) { + aPersModel[pm]->chromRG.badErr=aPersModel[pm]->chromG.badErr=aPersModel[pm]->chromBG.badErr=true; + filtered++; + } + } + + //printf("Filtered %.1f%% frames for maxAvgDevFac %g leaving %i\n", filtered*100./(baseCount+chromCount+vignetteCount), maxAvgDevFac, baseCount+chromCount+vignetteCount-filtered); + } + + return filtered; +} + + +// mode: 0=vignette, 1=distortion, 2=CA +void LCPProfile::calcParams(int mode, float focalLength, float focusDist, float aperture, LCPModelCommon *pCorr1, LCPModelCommon *pCorr2, LCPModelCommon *pCorr3) const { + float euler=exp(1.0); + + // find the frames with the least distance, focal length wise + LCPPersModel *pLow=NULL, *pHigh=NULL; + + float focalLengthLog=log(focalLength); //, apertureLog=aperture>0 ? log(aperture) : 0; + float focusDistLog=focusDist>0? log(focusDist)+euler : 0; + + // Pass 1: determining best focal length, if possible different focusDistances (for the focDist is not given case) + for (int pm=0;pmfocLen; + + if (aPersModel[pm]->hasModeData(mode)) { + if (f <= focalLength && (pLow==NULL || f > pLow->focLen || (focusDist==0 && f==pLow->focLen && pLow->focDist>aPersModel[pm]->focDist))) { + pLow=aPersModel[pm]; + } + if (f >= focalLength && (pHigh==NULL || f < pHigh->focLen || (focusDist==0 && f==pHigh->focLen && pHigh->focDistfocDist))) { + pHigh=aPersModel[pm]; + } + } + } + + if (!pLow) + pLow=pHigh; + else if (!pHigh) + pHigh=pLow; + else { + // Pass 2: We have some, so take the best aperture for vignette and best focus for CA and distortion + // there are usually several frame per focal length. In the end pLow will have both flen and apterure/focdis below the target, + // and vice versa pHigh + float bestFocLenLow=pLow->focLen, bestFocLenHigh=pHigh->focLen; + + for (int pm=0;pmaperture; // float aperLog=log(aper); + float focDist=aPersModel[pm]->focDist; float focDistLog=log(focDist)+euler; + double meanErr; + + if (aPersModel[pm]->hasModeData(mode)) { + if (mode==0) { + meanErr=aPersModel[pm]->vignette.meanErr; + + // by aperture (vignette), and max out focus distance + // tests showed doing this by log(aperture) is not as advisable + if (aPersModel[pm]->focLen==bestFocLenLow && ( + (aper==aperture && pLow->vignette.meanErr>meanErr) + || (aper>=aperture && aperaperture && pLow->aperture > aperture) + || (aper<=aperture && (pLow->aperture>aperture || fabs(aperture-aper)aperture))))) { + pLow=aPersModel[pm]; + } + if (aPersModel[pm]->focLen==bestFocLenHigh && ( + (aper==aperture && pHigh->vignette.meanErr>meanErr) + || (aper<=aperture && aper>pHigh->aperture && pHigh->aperture < aperture) + || (aper>=aperture && (pHigh->apertureaperture))))) { + pHigh=aPersModel[pm]; + } + } else { + meanErr = (mode==1 ? aPersModel[pm]->base.meanErr : aPersModel[pm]->chromG.meanErr); + + if (focusDist>0) { + // by focus distance + if (aPersModel[pm]->focLen==bestFocLenLow && ( + (focDist==focusDist && (mode==1 ? pLow->base.meanErr : pLow->chromG.meanErr)>meanErr) + || (focDist>=focusDist && focDistfocDist && pLow->focDist > focusDist) + || (focDist<=focusDist && (pLow->focDist>focusDist || fabs(focusDistLog-focDistLog)focDist)+euler)))))) { + pLow=aPersModel[pm]; + } + if (aPersModel[pm]->focLen==bestFocLenHigh && ( + (focDist==focusDist && (mode==1 ? pHigh->base.meanErr : pHigh->chromG.meanErr)>meanErr) + || (focDist<=focusDist && focDist>pHigh->focDist && pHigh->focDist < focusDist) + || (focDist>=focusDist && (pHigh->focDistfocDist)+euler)))))) { + pHigh=aPersModel[pm]; + } + } else { + // no focus distance available, just error + if (aPersModel[pm]->focLen==bestFocLenLow && (mode==1 ? pLow->base.meanErr : pLow->chromG.meanErr)>meanErr) { + pLow=aPersModel[pm]; + } + if (aPersModel[pm]->focLen==bestFocLenHigh && (mode==1 ? pHigh->base.meanErr : pHigh->chromG.meanErr)>meanErr) { + pHigh=aPersModel[pm]; + } + } + } + } + } + } + + if (pLow!=NULL && pHigh!=NULL) { + // average out the factors, linear interpolation in logarithmic scale + float facLow=0.5; + bool focLenOnSpot=false; // pretty often, since max/min are often as frames in LCP + + // There is as foclen range, take that as basis + if (pLow->focLen < pHigh->focLen) { + facLow = (log(pHigh->focLen)-focalLengthLog) / (log(pHigh->focLen) - log(pLow->focLen)); + } else { + focLenOnSpot=pLow->focLen==pHigh->focLen && pLow->focLen==focalLength; + } + + // and average the other factor if available + if (mode==0 && pLow->aperture < aperture && pHigh->aperture > aperture) { + // Mix in aperture + float facAperLow = (pHigh->aperture - aperture) / (pHigh->aperture - pLow->aperture); + facLow = focLenOnSpot ? facAperLow : (0.5*facLow + 0.5*facAperLow); + } else if (mode!=0 && focusDist>0 && pLow->focDist < focusDist && pHigh->focDist > focusDist) { + // focus distance for all else (if focus distance is given) + float facDistLow = (log(pHigh->focDist)+euler - focusDistLog) / (log(pHigh->focDist) - log(pLow->focDist)); + facLow = focLenOnSpot ? facDistLow : (0.8*facLow + 0.2*facDistLow); + } + + switch (mode) { + case 0: // vignette + pCorr1->merge(pLow->vignette, pHigh->vignette, facLow); + break; + + case 1: // distortion + pCorr1->merge(pLow->base, pHigh->base, facLow); + break; + + case 2: // CA + pCorr1->merge(pLow->chromRG, pHigh->chromRG, facLow); + pCorr2->merge(pLow->chromG, pHigh->chromG, facLow); + pCorr3->merge(pLow->chromBG, pHigh->chromBG, facLow); + break; + } + + //printf("LCP mode=%i, dist: %g found frames: Fno %g-%g; FocLen %g-%g; Dist %g-%g with weight %g\n", mode, focusDist, pLow->aperture, pHigh->aperture, pLow->focLen, pHigh->focLen, pLow->focDist, pHigh->focDist, facLow); + } else printf("Error: LCP file contained no %s parameters\n",mode==0 ? "vignette" : mode == 1 ? "distortion" : "CA" ); +} + +void LCPProfile::print() const { + printf("=== Profile %s\n", profileName.c_str()); + printf("Frames: %i, RAW: %i; Fisheye: %i; Sensorformat: %f\n",persModelCount,isRaw,isFisheye,sensorFormatFactor); + for (int pm=0;pmprint(); +} + +void XMLCALL LCPProfile::XmlStartHandler(void *pLCPProfile, const char *el, const char **attr) { + LCPProfile *pProf=static_cast(pLCPProfile); + bool parseAttr=false; + + if (*pProf->inInvalidTag) return; // We ignore everything in dirty tag till it's gone + + // clean up tagname + const char* src=strrchr(el,':'); + if (src==NULL) src=const_cast(el); else src++; + + strcpy(pProf->lastTag,src); + + if (!strcmp("VignetteModelPiecewiseParam",src)) strcpy(pProf->inInvalidTag,src); + + if (!strcmp("CameraProfiles",src)) pProf->inCamProfiles=true; + if (!strcmp("AlternateLensIDs",src)) pProf->inAlternateLensID=true; + if (!strcmp("AlternateLensNames",src)) pProf->inAlternateLensNames=true; + if (!pProf->inCamProfiles || pProf->inAlternateLensID || pProf->inAlternateLensNames) return; + + if (!strcmp("li",src)) { + pProf->pCurPersModel=new LCPPersModel(); + pProf->pCurCommon=&pProf->pCurPersModel->base; // iterated to next tags within persModel + return; + } + + if (!strcmp("PerspectiveModel",src)) { + pProf->firstLIDone=true; pProf->inPerspect=true; + return; + } else if (!strcmp("FisheyeModel",src)) { + pProf->firstLIDone=true; pProf->inPerspect=true; + pProf->isFisheye=true; // just misses third param, and different path, rest is the same + return; + } else if (!strcmp("Description",src)) parseAttr=true; + + // Move pointer to general section + if (pProf->inPerspect) { + if (!strcmp("ChromaticRedGreenModel",src)) { + pProf->pCurCommon=&pProf->pCurPersModel->chromRG; + parseAttr=true; + } else if (!strcmp("ChromaticGreenModel",src)) { + pProf->pCurCommon=&pProf->pCurPersModel->chromG; + parseAttr=true; + } else if (!strcmp("ChromaticBlueGreenModel",src)) { + pProf->pCurCommon=&pProf->pCurPersModel->chromBG; + parseAttr=true; } else if (!strcmp("VignetteModel",src)) { - pProf->pCurCommon=&pProf->pCurPersModel->vignette; - parseAttr=true; - } - } - - // some profiles (espc. Pentax) have a different structure that is attributes based - // simulate tags by feeding them in - if (parseAttr && attr!=NULL) { - for (int i = 0; attr[i]; i += 2) { - const char* nameStart=strrchr(attr[i],':'); - if (nameStart==NULL) nameStart=const_cast(attr[i]); else nameStart++; - - strcpy(pProf->lastTag, nameStart); - XmlTextHandler(pLCPProfile, attr[i+1], strlen(attr[i+1])); - } - } -} - -void XMLCALL LCPProfile::XmlTextHandler(void *pLCPProfile, const XML_Char *s, int len) { - LCPProfile *pProf=static_cast(pLCPProfile); - - if (!pProf->inCamProfiles || pProf->inAlternateLensID || pProf->inAlternateLensNames || *pProf->inInvalidTag) return; - - // Check if it contains non-whitespaces (there are several calls to this for one tag unfortunately) - bool onlyWhiteSpace=true; - int i=0; - while (ilastTag; - - // Common data section - if (!pProf->firstLIDone) { - // Generic tags are the same for all - if (!strcmp("ProfileName",tag)) - pProf->profileName=Glib::ustring(raw); - else if (!strcmp("Model",tag)) - pProf->camera=Glib::ustring(raw); - else if (!strcmp("Lens",tag)) - pProf->lens=Glib::ustring(raw); - else if (!strcmp("CameraPrettyName",tag)) - pProf->cameraPrettyName=Glib::ustring(raw); - else if (!strcmp("LensPrettyName",tag)) - pProf->lensPrettyName=Glib::ustring(raw); - else if (!strcmp("CameraRawProfile",tag)) - pProf->isRaw=!strcmp("True",raw); - } - - // --- Now all floating points. Must replace local dot characters - // WARNING: called by different threads, that may run on different local settings, - // so don't use system params - if (atof("1,2345")==1.2345) { - char* p=raw; - while (*p) { - if (*p=='.') *p=','; - p++; - } - } - - if (!pProf->firstLIDone) { - if (!strcmp("SensorFormatFactor",tag)) - pProf->sensorFormatFactor=atof(raw); - } - - // Perspective model base data - if (!strcmp("FocalLength",tag)) - pProf->pCurPersModel->focLen=atof(raw); - else if (!strcmp("FocusDistance",tag)) { - double focDist=atof(raw); - pProf->pCurPersModel->focDist=focDist<10000?focDist:10000; - } - else if (!strcmp("ApertureValue",tag)) - pProf->pCurPersModel->aperture=atof(raw); - - // Section depended - if (!strcmp("FocalLengthX",tag)) - pProf->pCurCommon->focLenX=atof(raw); - else if (!strcmp("FocalLengthY",tag)) - pProf->pCurCommon->focLenY=atof(raw); - else if (!strcmp("ImageXCenter",tag)) - pProf->pCurCommon->imgXCenter=atof(raw); - else if (!strcmp("ImageYCenter",tag)) - pProf->pCurCommon->imgYCenter=atof(raw); - else if (!strcmp("ScaleFactor",tag)) - pProf->pCurCommon->scaleFac=atof(raw); - else if (!strcmp("ResidualMeanError",tag)) - pProf->pCurCommon->meanErr=atof(raw); + pProf->pCurCommon=&pProf->pCurPersModel->vignette; + parseAttr=true; + } + } + + // some profiles (espc. Pentax) have a different structure that is attributes based + // simulate tags by feeding them in + if (parseAttr && attr!=NULL) { + for (int i = 0; attr[i]; i += 2) { + const char* nameStart=strrchr(attr[i],':'); + if (nameStart==NULL) nameStart=const_cast(attr[i]); else nameStart++; + + strcpy(pProf->lastTag, nameStart); + XmlTextHandler(pLCPProfile, attr[i+1], strlen(attr[i+1])); + } + } +} + +void XMLCALL LCPProfile::XmlTextHandler(void *pLCPProfile, const XML_Char *s, int len) { + LCPProfile *pProf=static_cast(pLCPProfile); + + if (!pProf->inCamProfiles || pProf->inAlternateLensID || pProf->inAlternateLensNames || *pProf->inInvalidTag) return; + + // Check if it contains non-whitespaces (there are several calls to this for one tag unfortunately) + bool onlyWhiteSpace=true; + int i=0; + while (ilastTag; + + // Common data section + if (!pProf->firstLIDone) { + // Generic tags are the same for all + if (!strcmp("ProfileName",tag)) + pProf->profileName=Glib::ustring(raw); + else if (!strcmp("Model",tag)) + pProf->camera=Glib::ustring(raw); + else if (!strcmp("Lens",tag)) + pProf->lens=Glib::ustring(raw); + else if (!strcmp("CameraPrettyName",tag)) + pProf->cameraPrettyName=Glib::ustring(raw); + else if (!strcmp("LensPrettyName",tag)) + pProf->lensPrettyName=Glib::ustring(raw); + else if (!strcmp("CameraRawProfile",tag)) + pProf->isRaw=!strcmp("True",raw); + } + + // --- Now all floating points. Must replace local dot characters + // WARNING: called by different threads, that may run on different local settings, + // so don't use system params + if (atof("1,2345")==1.2345) { + char* p=raw; + while (*p) { + if (*p=='.') *p=','; + p++; + } + } + + if (!pProf->firstLIDone) { + if (!strcmp("SensorFormatFactor",tag)) + pProf->sensorFormatFactor=atof(raw); + } + + // Perspective model base data + if (!strcmp("FocalLength",tag)) + pProf->pCurPersModel->focLen=atof(raw); + else if (!strcmp("FocusDistance",tag)) { + double focDist=atof(raw); + pProf->pCurPersModel->focDist=focDist<10000?focDist:10000; + } + else if (!strcmp("ApertureValue",tag)) + pProf->pCurPersModel->aperture=atof(raw); + + // Section depended + if (!strcmp("FocalLengthX",tag)) + pProf->pCurCommon->focLenX=atof(raw); + else if (!strcmp("FocalLengthY",tag)) + pProf->pCurCommon->focLenY=atof(raw); + else if (!strcmp("ImageXCenter",tag)) + pProf->pCurCommon->imgXCenter=atof(raw); + else if (!strcmp("ImageYCenter",tag)) + pProf->pCurCommon->imgYCenter=atof(raw); + else if (!strcmp("ScaleFactor",tag)) + pProf->pCurCommon->scaleFac=atof(raw); + else if (!strcmp("ResidualMeanError",tag)) + pProf->pCurCommon->meanErr=atof(raw); else if (!strcmp("RadialDistortParam1",tag) || !strcmp("VignetteModelParam1",tag)) pProf->pCurCommon->param[0]=atof(raw); - else if (!strcmp("RadialDistortParam2",tag) || !strcmp("VignetteModelParam2",tag)) - pProf->pCurCommon->param[1]=atof(raw); - else if (!strcmp("RadialDistortParam3",tag) || !strcmp("VignetteModelParam3",tag)) - pProf->pCurCommon->param[2]=atof(raw); - else if (!strcmp("RadialDistortParam4",tag) || !strcmp("TangentialDistortParam1",tag)) - pProf->pCurCommon->param[3]=atof(raw); - else if (!strcmp("RadialDistortParam5",tag) || !strcmp("TangentialDistortParam2",tag)) - pProf->pCurCommon->param[4]=atof(raw); -} - -void XMLCALL LCPProfile::XmlEndHandler(void *pLCPProfile, const char *el) { - LCPProfile *pProf=static_cast(pLCPProfile); - - // We ignore everything in dirty tag till it's gone - if (*pProf->inInvalidTag) { - if (strstr(el,pProf->inInvalidTag)) *pProf->inInvalidTag=0; - return; - } - - if (strstr(el,":CameraProfiles")) pProf->inCamProfiles=false; - if (strstr(el,":AlternateLensIDs")) pProf->inAlternateLensID=false; - if (strstr(el,":AlternateLensNames")) pProf->inAlternateLensNames=false; - - if (!pProf->inCamProfiles || pProf->inAlternateLensID || pProf->inAlternateLensNames) return; - - if (strstr(el,":PerspectiveModel") || strstr(el,":FisheyeModel")) - pProf->inPerspect=false; - else if (strstr(el, ":li")) { - pProf->aPersModel[pProf->persModelCount]=pProf->pCurPersModel; - pProf->pCurPersModel=NULL; - pProf->persModelCount++; - } -} - -// Generates as singleton -LCPStore* LCPStore::getInstance() -{ - static LCPStore* instance_ = 0; - if ( instance_ == 0 ) - { - static MyMutex smutex_; - MyMutex::MyLock lock(smutex_); - if ( instance_ == 0 ) - { - instance_ = new LCPStore(); - } - } - return instance_; -} - -LCPProfile* LCPStore::getProfile (Glib::ustring filename) { - if (filename.length()==0 || !isValidLCPFileName(filename)) return NULL; - - MyMutex::MyLock lock(mtx); - - std::map::iterator r = profileCache.find (filename); - if (r!=profileCache.end()) return r->second; - - // Add profile (if exists) - profileCache[filename]=new LCPProfile(filename); - //profileCache[filename]->print(); - return profileCache[filename]; -} - -bool LCPStore::isValidLCPFileName(Glib::ustring filename) const { - if (!safe_file_test (filename, Glib::FILE_TEST_EXISTS) || safe_file_test (filename, Glib::FILE_TEST_IS_DIR)) return false; - size_t pos=filename.find_last_of ('.'); - return pos>0 && !filename.casefold().compare (pos, 4, ".lcp"); -} - -Glib::ustring LCPStore::getDefaultCommonDirectory() const { - Glib::ustring dir; - -#ifdef WIN32 - WCHAR pathW[MAX_PATH]={0}; char pathA[MAX_PATH]; - - if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_COMMON_APPDATA,false)) { - char pathA[MAX_PATH]; - WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); - Glib::ustring fullDir=Glib::ustring(pathA)+Glib::ustring("\\Adobe\\CameraRaw\\LensProfiles\\1.0"); - if (safe_file_test(fullDir, Glib::FILE_TEST_IS_DIR)) dir=fullDir; - } -#endif - - // TODO: Add Mac paths here - - return dir; -} + else if (!strcmp("RadialDistortParam2",tag) || !strcmp("VignetteModelParam2",tag)) + pProf->pCurCommon->param[1]=atof(raw); + else if (!strcmp("RadialDistortParam3",tag) || !strcmp("VignetteModelParam3",tag)) + pProf->pCurCommon->param[2]=atof(raw); + else if (!strcmp("RadialDistortParam4",tag) || !strcmp("TangentialDistortParam1",tag)) + pProf->pCurCommon->param[3]=atof(raw); + else if (!strcmp("RadialDistortParam5",tag) || !strcmp("TangentialDistortParam2",tag)) + pProf->pCurCommon->param[4]=atof(raw); +} + +void XMLCALL LCPProfile::XmlEndHandler(void *pLCPProfile, const char *el) { + LCPProfile *pProf=static_cast(pLCPProfile); + + // We ignore everything in dirty tag till it's gone + if (*pProf->inInvalidTag) { + if (strstr(el,pProf->inInvalidTag)) *pProf->inInvalidTag=0; + return; + } + + if (strstr(el,":CameraProfiles")) pProf->inCamProfiles=false; + if (strstr(el,":AlternateLensIDs")) pProf->inAlternateLensID=false; + if (strstr(el,":AlternateLensNames")) pProf->inAlternateLensNames=false; + + if (!pProf->inCamProfiles || pProf->inAlternateLensID || pProf->inAlternateLensNames) return; + + if (strstr(el,":PerspectiveModel") || strstr(el,":FisheyeModel")) + pProf->inPerspect=false; + else if (strstr(el, ":li")) { + pProf->aPersModel[pProf->persModelCount]=pProf->pCurPersModel; + pProf->pCurPersModel=NULL; + pProf->persModelCount++; + } +} + +// Generates as singleton +LCPStore* LCPStore::getInstance() +{ + static LCPStore* instance_ = 0; + if ( instance_ == 0 ) + { + static MyMutex smutex_; + MyMutex::MyLock lock(smutex_); + if ( instance_ == 0 ) + { + instance_ = new LCPStore(); + } + } + return instance_; +} + +LCPProfile* LCPStore::getProfile (Glib::ustring filename) { + if (filename.length()==0 || !isValidLCPFileName(filename)) return NULL; + + MyMutex::MyLock lock(mtx); + + std::map::iterator r = profileCache.find (filename); + if (r!=profileCache.end()) return r->second; + + // Add profile (if exists) + profileCache[filename]=new LCPProfile(filename); + //profileCache[filename]->print(); + return profileCache[filename]; +} + +bool LCPStore::isValidLCPFileName(Glib::ustring filename) const { + if (!safe_file_test (filename, Glib::FILE_TEST_EXISTS) || safe_file_test (filename, Glib::FILE_TEST_IS_DIR)) return false; + size_t pos=filename.find_last_of ('.'); + return pos>0 && !filename.casefold().compare (pos, 4, ".lcp"); +} + +Glib::ustring LCPStore::getDefaultCommonDirectory() const { + Glib::ustring dir; + +#ifdef WIN32 + WCHAR pathW[MAX_PATH]={0}; char pathA[MAX_PATH]; + + if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_COMMON_APPDATA,false)) { + char pathA[MAX_PATH]; + WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); + Glib::ustring fullDir=Glib::ustring(pathA)+Glib::ustring("\\Adobe\\CameraRaw\\LensProfiles\\1.0"); + if (safe_file_test(fullDir, Glib::FILE_TEST_IS_DIR)) dir=fullDir; + } +#endif + + // TODO: Add Mac paths here + + return dir; +} diff --git a/rtengine/myfile.cc b/rtengine/myfile.cc index 49372942d..e5c6d2514 100644 --- a/rtengine/myfile.cc +++ b/rtengine/myfile.cc @@ -312,38 +312,38 @@ void fclose (IMFILE* f) { } int fscanf (IMFILE* f, const char* s ...) { - // fscanf not easily wrapped since we have no terminating \0 at end - // of file data and vsscanf() won't tell us how many characters that - // were parsed. However, only dcraw.cc code use it and only for "%f" and - // "%d", so we make a dummy fscanf here just to support dcraw case. - char buf[50], *endptr; - int copy_sz = f->size - f->pos; - if (copy_sz > sizeof(buf)) { - copy_sz = sizeof(buf) - 1; - } - memcpy(buf, &f->data[f->pos], copy_sz); - buf[copy_sz] = '\0'; - va_list ap; - va_start (ap, s); - if (strcmp(s, "%d") == 0) { - int i = strtol(buf, &endptr, 10); - if (endptr == buf) { - return 0; - } - int *pi = va_arg(ap, int*); - *pi = i; - } else if (strcmp(s, "%f") == 0) { - float f = strtof(buf, &endptr); - if (endptr == buf) { - return 0; - } - float *pf = va_arg(ap, float*); - *pf = f; - } - va_end (ap); - f->pos += endptr - buf; - return 1; -} + // fscanf not easily wrapped since we have no terminating \0 at end + // of file data and vsscanf() won't tell us how many characters that + // were parsed. However, only dcraw.cc code use it and only for "%f" and + // "%d", so we make a dummy fscanf here just to support dcraw case. + char buf[50], *endptr; + int copy_sz = f->size - f->pos; + if (copy_sz > sizeof(buf)) { + copy_sz = sizeof(buf) - 1; + } + memcpy(buf, &f->data[f->pos], copy_sz); + buf[copy_sz] = '\0'; + va_list ap; + va_start (ap, s); + if (strcmp(s, "%d") == 0) { + int i = strtol(buf, &endptr, 10); + if (endptr == buf) { + return 0; + } + int *pi = va_arg(ap, int*); + *pi = i; + } else if (strcmp(s, "%f") == 0) { + float f = strtof(buf, &endptr); + if (endptr == buf) { + return 0; + } + float *pf = va_arg(ap, float*); + *pf = f; + } + va_end (ap); + f->pos += endptr - buf; + return 1; +} char* fgets (char* s, int n, IMFILE* f) { diff --git a/rtengine/previewimage.cc b/rtengine/previewimage.cc index 3024a05a4..480d228f5 100644 --- a/rtengine/previewimage.cc +++ b/rtengine/previewimage.cc @@ -1,193 +1,193 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include "previewimage.h" -#include "iimage.h" -#include "utils.h" -#include "iimage.h" -#include "rtthumbnail.h" -#include "rawimagesource.h" -#include "StopWatch.h" - -using namespace rtengine; -using namespace procparams; - -PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext, const PreviewImageMode mode) { - rtengine::Thumbnail* tpp=NULL; - - if (mode==PIM_EmbeddedPreviewOnly || mode==PIM_EmbeddedOrRaw) { - - const unsigned char *data = NULL; - - int width=-1, height=-1; - if (ext.lowercase()=="jpg" || ext.lowercase()=="jpeg") { - // int deg = infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); - if (tpp) - data = tpp->getImage8Data(); - } - else if (ext.lowercase()=="png") { - tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); - if (tpp) - data = tpp->getImage8Data(); - } - else if (ext.lowercase()=="tif" || ext.lowercase()=="tiff") { - // int deg = infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); - if (tpp) - data = tpp->getImage8Data(); - } - else { - rtengine::RawMetaDataLocation ri; - tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, width, height, 1, true, true); - if (tpp) - data = tpp->getImage8Data(); - } - - if (tpp) { - if (data) { - int w, h; - double scale = 1.; - if (tpp) - tpp->getDimensions(w, h, scale); - previewImage = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24, w, h); - previewImage->flush(); - -#pragma omp parallel -{ - const unsigned char *src; - unsigned char *dst; -#pragma omp for schedule(static,10) - for (unsigned int i=0; i<(unsigned int)(h); i++) { - src = data + i*w*3; - dst = previewImage->get_data() + i*w*4; - for (unsigned int j=0; j<(unsigned int)(w); j++) { - unsigned char r = *(src++); - unsigned char g = *(src++); - unsigned char b = *(src++); - -#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - *(dst++) = b; - *(dst++) = g; - *(dst++) = r; - *(dst++) = 0; -#else - *(dst++) = 0; - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; -#endif - } - } -} - previewImage->mark_dirty(); - } - } - } - - if ((mode==PIM_EmbeddedOrRaw && !tpp) || mode==PIM_ForceRaw) { - RawImageSource rawImage; - int error = rawImage.load(fname, true); - if (!error) { - rtengine::Image8 *output = NULL; - const unsigned char *data = NULL; - int fw, fh; - procparams::ProcParams params; - /*rtengine::RAWParams raw; - rtengine::LensProfParams lensProf; - rtengine::procparams::ToneCurveParams toneCurve; - rtengine::procparams::ColorManagementParams icm; - rtengine::CoarseTransformParams coarse;*/ - ColorTemp wb = rawImage.getWB (); - rawImage.getFullSize (fw, fh, TR_NONE); - PreviewProps pp (0, 0, fw, fh, 1); - params.icm.input = Glib::ustring("(embedded)"); - params.raw.bayersensor.method = RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::fast]; - params.raw.deadPixelFilter = false; - params.raw.ca_autocorrect = false; - params.raw.xtranssensor.method = RAWParams::XTransSensor::methodstring[RAWParams::XTransSensor::fast]; - rawImage.preprocess(params.raw, params.lensProf, params.coarse); - rawImage.demosaic(params.raw); - Imagefloat* image = new rtengine::Imagefloat (fw, fh); - rawImage.getImage (wb, TR_NONE, image, pp, params.toneCurve, params.icm, params.raw); - output = new Image8(fw, fh); - rawImage.convertColorSpace(image, params.icm, wb); - StopWatch Stop1("inspector loop"); -#pragma omp parallel for schedule(dynamic, 10) - for (int i=0; ir(i,j) = Color::gamma2curve[image->r(i,j)]; - image->g(i,j) = Color::gamma2curve[image->g(i,j)]; - image->b(i,j) = Color::gamma2curve[image->b(i,j)]; - } - Stop1.stop(); - - image->resizeImgTo(fw, fh, TI_Nearest, output); - data = output->getData(); - - - if (data) { - int w, h; - double scale = 1.; - w = output->getWidth(); - h = output->getHeight(); - previewImage = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24, w, h); - previewImage->flush(); - -#pragma omp parallel -{ - const unsigned char *src; - unsigned char *dst; -#pragma omp for schedule(static,10) - for (unsigned int i=0; i<(unsigned int)(h); i++) { - src = data + i*w*3; - dst = previewImage->get_data() + i*w*4; - for (unsigned int j=0; j<(unsigned int)(w); j++) { - unsigned char r = *(src++); - unsigned char g = *(src++); - unsigned char b = *(src++); -#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - *(dst++) = b; - *(dst++) = g; - *(dst++) = r; - *(dst++) = 0; -#else - *(dst++) = 0; - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; -#endif - } - } -} - if (output) - delete output; - previewImage->mark_dirty(); - } - } - } - - if (tpp) - delete tpp; - -} - -Cairo::RefPtr PreviewImage::getImage() { - return previewImage; -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "previewimage.h" +#include "iimage.h" +#include "utils.h" +#include "iimage.h" +#include "rtthumbnail.h" +#include "rawimagesource.h" +#include "StopWatch.h" + +using namespace rtengine; +using namespace procparams; + +PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext, const PreviewImageMode mode) { + rtengine::Thumbnail* tpp=NULL; + + if (mode==PIM_EmbeddedPreviewOnly || mode==PIM_EmbeddedOrRaw) { + + const unsigned char *data = NULL; + + int width=-1, height=-1; + if (ext.lowercase()=="jpg" || ext.lowercase()=="jpeg") { + // int deg = infoFromImage (fname); + tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); + if (tpp) + data = tpp->getImage8Data(); + } + else if (ext.lowercase()=="png") { + tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); + if (tpp) + data = tpp->getImage8Data(); + } + else if (ext.lowercase()=="tif" || ext.lowercase()=="tiff") { + // int deg = infoFromImage (fname); + tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); + if (tpp) + data = tpp->getImage8Data(); + } + else { + rtengine::RawMetaDataLocation ri; + tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, width, height, 1, true, true); + if (tpp) + data = tpp->getImage8Data(); + } + + if (tpp) { + if (data) { + int w, h; + double scale = 1.; + if (tpp) + tpp->getDimensions(w, h, scale); + previewImage = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24, w, h); + previewImage->flush(); + +#pragma omp parallel +{ + const unsigned char *src; + unsigned char *dst; +#pragma omp for schedule(static,10) + for (unsigned int i=0; i<(unsigned int)(h); i++) { + src = data + i*w*3; + dst = previewImage->get_data() + i*w*4; + for (unsigned int j=0; j<(unsigned int)(w); j++) { + unsigned char r = *(src++); + unsigned char g = *(src++); + unsigned char b = *(src++); + +#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ + *(dst++) = b; + *(dst++) = g; + *(dst++) = r; + *(dst++) = 0; +#else + *(dst++) = 0; + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; +#endif + } + } +} + previewImage->mark_dirty(); + } + } + } + + if ((mode==PIM_EmbeddedOrRaw && !tpp) || mode==PIM_ForceRaw) { + RawImageSource rawImage; + int error = rawImage.load(fname, true); + if (!error) { + rtengine::Image8 *output = NULL; + const unsigned char *data = NULL; + int fw, fh; + procparams::ProcParams params; + /*rtengine::RAWParams raw; + rtengine::LensProfParams lensProf; + rtengine::procparams::ToneCurveParams toneCurve; + rtengine::procparams::ColorManagementParams icm; + rtengine::CoarseTransformParams coarse;*/ + ColorTemp wb = rawImage.getWB (); + rawImage.getFullSize (fw, fh, TR_NONE); + PreviewProps pp (0, 0, fw, fh, 1); + params.icm.input = Glib::ustring("(embedded)"); + params.raw.bayersensor.method = RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::fast]; + params.raw.deadPixelFilter = false; + params.raw.ca_autocorrect = false; + params.raw.xtranssensor.method = RAWParams::XTransSensor::methodstring[RAWParams::XTransSensor::fast]; + rawImage.preprocess(params.raw, params.lensProf, params.coarse); + rawImage.demosaic(params.raw); + Imagefloat* image = new rtengine::Imagefloat (fw, fh); + rawImage.getImage (wb, TR_NONE, image, pp, params.toneCurve, params.icm, params.raw); + output = new Image8(fw, fh); + rawImage.convertColorSpace(image, params.icm, wb); + StopWatch Stop1("inspector loop"); +#pragma omp parallel for schedule(dynamic, 10) + for (int i=0; ir(i,j) = Color::gamma2curve[image->r(i,j)]; + image->g(i,j) = Color::gamma2curve[image->g(i,j)]; + image->b(i,j) = Color::gamma2curve[image->b(i,j)]; + } + Stop1.stop(); + + image->resizeImgTo(fw, fh, TI_Nearest, output); + data = output->getData(); + + + if (data) { + int w, h; + double scale = 1.; + w = output->getWidth(); + h = output->getHeight(); + previewImage = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24, w, h); + previewImage->flush(); + +#pragma omp parallel +{ + const unsigned char *src; + unsigned char *dst; +#pragma omp for schedule(static,10) + for (unsigned int i=0; i<(unsigned int)(h); i++) { + src = data + i*w*3; + dst = previewImage->get_data() + i*w*4; + for (unsigned int j=0; j<(unsigned int)(w); j++) { + unsigned char r = *(src++); + unsigned char g = *(src++); + unsigned char b = *(src++); +#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ + *(dst++) = b; + *(dst++) = g; + *(dst++) = r; + *(dst++) = 0; +#else + *(dst++) = 0; + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; +#endif + } + } +} + if (output) + delete output; + previewImage->mark_dirty(); + } + } + } + + if (tpp) + delete tpp; + +} + +Cairo::RefPtr PreviewImage::getImage() { + return previewImage; +} diff --git a/rtengine/previewimage.h b/rtengine/previewimage.h index 6f78dc960..46c90b0b8 100644 --- a/rtengine/previewimage.h +++ b/rtengine/previewimage.h @@ -1,54 +1,54 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _PREVIEWIMAGE_ -#define _PREVIEWIMAGE_ - -#include -#include "cairomm/cairomm.h" - -namespace rtengine { - -/** @brief Get a quick preview image out of a raw or standard file - * - * This class reads the full size preview image (at least the biggest one available) from the raw file, - * or the fast demosaiced version if no suitable embedded preview is found. - * - * For standard image, it simply read it with fast conversion for 32 bits images - */ -class PreviewImage { - -private: - Cairo::RefPtr previewImage; - -public: - typedef enum mode { - PIM_EmbeddedPreviewOnly, /// Get the embedded image only, fail if doesn't exist - PIM_EmbeddedOrRaw, /// Get the embedded image if it exist, or use the raw file otherwise - PIM_ForceRaw /// Get a preview of the raw file, even if an embedded image exist - } PreviewImageMode; - - PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext, const PreviewImageMode mode); - - Cairo::RefPtr getImage(); - -}; - -} - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _PREVIEWIMAGE_ +#define _PREVIEWIMAGE_ + +#include +#include "cairomm/cairomm.h" + +namespace rtengine { + +/** @brief Get a quick preview image out of a raw or standard file + * + * This class reads the full size preview image (at least the biggest one available) from the raw file, + * or the fast demosaiced version if no suitable embedded preview is found. + * + * For standard image, it simply read it with fast conversion for 32 bits images + */ +class PreviewImage { + +private: + Cairo::RefPtr previewImage; + +public: + typedef enum mode { + PIM_EmbeddedPreviewOnly, /// Get the embedded image only, fail if doesn't exist + PIM_EmbeddedOrRaw, /// Get the embedded image if it exist, or use the raw file otherwise + PIM_ForceRaw /// Get a preview of the raw file, even if an embedded image exist + } PreviewImageMode; + + PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext, const PreviewImageMode mode); + + Cairo::RefPtr getImage(); + +}; + +} + +#endif diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 563a0c980..3638ebeca 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -330,8 +330,8 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene this->rotate_deg = 180; else if (flip==6) this->rotate_deg = 90; - else if (flip % 90 == 0 && flip < 360) - this->rotate_deg = flip; + else if (flip % 90 == 0 && flip < 360) + this->rotate_deg = flip; else this->rotate_deg = 0; diff --git a/rtengine/safegtk.cc b/rtengine/safegtk.cc index 71105b6af..d0931f4a1 100644 --- a/rtengine/safegtk.cc +++ b/rtengine/safegtk.cc @@ -1,507 +1,507 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * Copyright (c) 2010 Sasha Vasko - * Copyright (c) 2010 Oliver Duis - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include "safegtk.h" -#include "../rtgui/guiutils.h" -#include -#include -#ifdef WIN32 -#include -// for GCC32 -#ifndef _WIN32_IE -#define _WIN32_IE 0x0600 -#endif -#include -#include -#else -#include -#endif -#include "../rtgui/rtimage.h" -#include - - -Glib::RefPtr safe_create_from_file(const Glib::ustring& filename) -{ - Glib::RefPtr res; - Glib::ustring path = RTImage::findIconAbsolutePath(filename); - if (path.length()) { - try { - res = Gdk::Pixbuf::create_from_file (path); - } - catch (Glib::Exception& ex) { - printf ("ERROR: (ustring) File \"%s\" not found.\n", ex.what().c_str()); - } - } - return res; -} - -Cairo::RefPtr safe_create_from_png(const Glib::ustring& filename) -{ - Cairo::RefPtr res; - Glib::ustring path = RTImage::findIconAbsolutePath(filename); - if (path.length()) { - // files_test need a std::string which (as stated in its proto) but will only work if - // we use the Glib::ustring filename !? - try { - // create_from_png need a std::string converted from UTF8 with safe_locale_from_utf8 - res = Cairo::ImageSurface::create_from_png (safe_locale_from_utf8(path)); - } catch (...) { - printf("ERROR: (ustring) File \"%s\" not found.\n", path.c_str()); - } - } - return res; -} - -Glib::RefPtr safe_query_file_info (Glib::RefPtr &file) -{ - Glib::RefPtr info; -#ifdef GLIBMM_EXCEPTIONS_ENABLED - try { info = file->query_info(); }catch (...) { } -#else - std::auto_ptr error; - info = file->query_info("*", Gio::FILE_QUERY_INFO_NONE, error); -#endif - return info; -} - -Glib::RefPtr safe_next_file (Glib::RefPtr &dirList) -{ - Glib::RefPtr info; -#ifdef GLIBMM_EXCEPTIONS_ENABLED - bool retry; - Glib::ustring last_error = ""; - do { - retry = false; - try { - info = dirList->next_file(); - } catch (Glib::Exception& ex) { - printf ("%s\n", ex.what().c_str()); - // API problem: not possible to differ between error looking at particular entry or - // general error scanning the directory. We do a hack by retrying and see if the - // error changes, if it does we can assume it's about the current filename and we - // should look at the next. More likely if a single file error is that the next - // retry is okay of course. - retry = (ex.what() != last_error); - last_error = ex.what(); - } - } while (retry); -#else - bool retry; - Glib::ustring last_error = ""; - do { - retry = false; - std::auto_ptr error; - Glib::RefPtr cancellable; - info = dirList->next_file(cancellable, error); - if (!info && error.get()) { - printf ("%s\n", error.what().c_str()); - retry = (error.what() != last_error); - last_error = error.what(); - } - } while (retry); -#endif - return info; -} - -#ifdef GLIBMM_EXCEPTIONS_ENABLED -# define SAFE_ENUMERATOR_CODE_START \ - do{try { if ((dirList = dir->enumerate_children ())) \ - for (Glib::RefPtr info = safe_next_file(dirList); info; info = safe_next_file(dirList)) { - -# define SAFE_ENUMERATOR_CODE_END \ - }} catch (Glib::Exception& ex) { printf ("%s\n", ex.what().c_str()); }}while(0) -#else -# define SAFE_ENUMERATOR_CODE_START \ - do{std::auto_ptr error; Glib::RefPtr cancellable; \ - if ((dirList = dir->enumerate_children (cancellable, "*", Gio::FILE_QUERY_INFO_NONE, error))) \ - for (Glib::RefPtr info = safe_next_file(dirList); info; info = safe_next_file(dirList)) { - -# define SAFE_ENUMERATOR_CODE_END } if (error.get()) printf ("%s\n", error->what().c_str());}while (0) -#endif - -#ifdef WIN32 - -// High speed Windows version -void safe_build_file_list (Glib::RefPtr &dir, std::vector &flist) -{ - Glib::ustring fullPath=dir->get_path() + Glib::ustring("\\*"); - - DWORD dwVersion=GetVersion(); - bool win7Plus=(LOBYTE(LOWORD(dwVersion))>6) || ((LOBYTE(LOWORD(dwVersion))==6) && HIBYTE(LOWORD(dwVersion))>=1); // 6.1 or better - - wchar_t *wDirName = (wchar_t*)g_utf8_to_utf16 (fullPath.c_str(), -1, NULL, NULL, NULL); - WIN32_FIND_DATAW fi; - - HANDLE hFF=FindFirstFileExW(wDirName, - //win7Plus ? FindExInfoBasic : // TODO: Add if MinGW is updated, makes it even faster - FindExInfoStandard,&fi, - FindExSearchNameMatch,NULL, - win7Plus ? 2 : 0); // Win7 large fetch - - if (hFF != INVALID_HANDLE_VALUE) { - do { - SYSTEMTIME stUTC; - FileTimeToSystemTime(&fi.ftLastWriteTime, &stUTC); - char time[64]; - sprintf(time,"%d-%02d-%02dT%02d:%02d:%02dZ",stUTC.wYear,stUTC.wMonth,stUTC.wDay,stUTC.wHour,stUTC.wMinute,stUTC.wSecond); - Glib::TimeVal timeVal; - timeVal.assign_from_iso8601(Glib::ustring(time)); - - char pathA[MAX_PATH]; - WideCharToMultiByte(CP_UTF8,0,(WCHAR*)fi.cFileName,-1,pathA,MAX_PATH,0,0); - flist.push_back (FileMTimeInfo (removeExtension(Glib::ustring(pathA)), timeVal)); - - } while (FindNextFileW(hFF, &fi)); - - FindClose(hFF); - } - - g_free(wDirName); -} -#else - -// Generic file list build -void safe_build_file_list (Glib::RefPtr &dir, std::vector &flist) -{ - Glib::RefPtr dirList; - if (dir) { - SAFE_ENUMERATOR_CODE_START - flist.push_back (FileMTimeInfo (removeExtension(info->get_name()), info->modification_time())); - SAFE_ENUMERATOR_CODE_END; - } -} -#endif -/* - * safe_build_file_list can now filter out at the source all files that doesn't have the extensions specified (if provided) - */ -void safe_build_file_list (Glib::RefPtr &dir, std::vector &names, const Glib::ustring &directory, const std::vector *extensions) -{ - Glib::RefPtr dirList; - - if (dir) { - if (!extensions) { - SAFE_ENUMERATOR_CODE_START - names.push_back (Glib::build_filename (directory, info->get_name())); - SAFE_ENUMERATOR_CODE_END; - } - else { - // convert extensions to lowercase in a new vector list - std::vector lcExtensions; - for (unsigned int i=0; isize(); i++) - lcExtensions.push_back ((*extensions)[i].lowercase()); - - SAFE_ENUMERATOR_CODE_START - // convert the current filename to lowercase in a new ustring - Glib::ustring fname = Glib::ustring(info->get_name()).lowercase(); - - size_t pos = fname.find_last_of('.'); - if (pos < (fname.length()-1)) { - // there is an extension to the filename - - Glib::ustring lcFileExt = fname.substr(pos+1).lowercase(); - - // look out if it has one of the retained extensions - for (size_t i=0; iget_name())); - break; - } - } - } - SAFE_ENUMERATOR_CODE_END; - } - } -} - - -void safe_build_subdir_list (Glib::RefPtr &dir, std::vector &subDirs, bool add_hidden) -{ - Glib::RefPtr dirList; - if (dir) - { - // CD-ROMs with no drive inserted are reported, but do not exist, causing RT to crash - if (!safe_file_test(dir->get_path(),Glib::FILE_TEST_EXISTS)) return; - - SAFE_ENUMERATOR_CODE_START - if (info->get_file_type() == Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || add_hidden)) - subDirs.push_back (info->get_name()); - SAFE_ENUMERATOR_CODE_END; - } -} - -/* - * For an unknown reason, Glib::filename_to_utf8 doesn't work on Windows, so we're using - * Glib::filename_to_utf8 for Linux/Apple and Glib::locale_to_utf8 for Windows - */ -Glib::ustring safe_filename_to_utf8 (const std::string& src) -{ - Glib::ustring utf8_str; -#ifdef WIN32 -#ifdef GLIBMM_EXCEPTIONS_ENABLED - try { - utf8_str = Glib::locale_to_utf8(src); - } - catch (const Glib::Error& e) { - utf8_str = Glib::convert_with_fallback(src, "UTF-8", "ISO-8859-1","?"); - } -#else - { - std::auto_ptr error; - utf8_str = locale_to_utf8(src, error); - if (error.get()) - utf8_str = Glib::convert_with_fallback(src, "UTF-8", "ISO-8859-1","?", error); - } -#endif //GLIBMM_EXCEPTIONS_ENABLED -#else - utf8_str = Glib::filename_to_utf8(src); -#endif - return utf8_str; -} - -Glib::ustring safe_locale_to_utf8 (const std::string& src) -{ - Glib::ustring utf8_str; -#ifdef GLIBMM_EXCEPTIONS_ENABLED - try { - utf8_str = Glib::locale_to_utf8(src); - } - catch (const Glib::Error& e) { - utf8_str = Glib::convert_with_fallback(src, "UTF-8", "ISO-8859-1","?"); - } -#else - { - std::auto_ptr error; - utf8_str = locale_to_utf8(src, error); - if (error.get()) - utf8_str = Glib::convert_with_fallback(src, "UTF-8", "ISO-8859-1","?", error); - } -#endif //GLIBMM_EXCEPTIONS_ENABLED - return utf8_str; -} - -std::string safe_locale_from_utf8 (const Glib::ustring& utf8_str) -{ - std::string str; -#ifdef GLIBMM_EXCEPTIONS_ENABLED - try { - str = Glib::locale_from_utf8(utf8_str); - } - catch (const Glib::Error& e) { - //str = Glib::convert_with_fallback(utf8_str, "ISO-8859-1", "UTF-8", "?"); - } -#else - { - std::auto_ptr error; - str = Glib::locale_from_utf8(utf8_str, error); - /*if (error.get()) - {str = Glib::convert_with_fallback(utf8_str, "ISO-8859-1", "UTF-8", "?", error);}*/ - } -#endif //GLIBMM_EXCEPTIONS_ENABLED - return str; -} - -bool safe_spawn_command_line_async (const Glib::ustring& cmd_utf8) -{ - std::string cmd; - bool success = false; -#ifdef GLIBMM_EXCEPTIONS_ENABLED - try { - cmd = Glib::filename_from_utf8(cmd_utf8); - printf ("command line: %s\n", cmd.c_str()); - Glib::spawn_command_line_async (cmd.c_str()); - success = true; - } catch (Glib::Exception& ex) { - printf ("%s\n", ex.what().c_str()); - } -#else - std::auto_ptr error; - cmd = Glib::filename_from_utf8(cmd_utf8, error); - if (!error.get()) { - printf ("command line: %s\n", cmd.c_str()); - Glib::spawn_command_line_async (cmd, error); - } - if (error.get()) - printf ("%s\n", error->what().c_str()); - else - success = true; -#endif - return success; -} - -bool safe_spawn_command_line_sync (const Glib::ustring& cmd_utf8) -{ - int exitStatus=-1; - try { - //cmd = Glib::filename_from_utf8(cmd_utf8); - printf ("command line: %s\n", cmd_utf8.c_str()); - - // if it crashes here on windows, make sure you have the GTK runtime files gspawn-win32-helper*.exe files in RT directory - Glib::spawn_command_line_sync (cmd_utf8, NULL, NULL, &exitStatus); - } catch (Glib::Exception& ex) { - printf ("%s\n", ex.what().c_str()); - } - return (exitStatus==0); -} - -// Opens a file for binary writing and request exclusive lock (cases were you need "wb" mode plus locking) -// (Important on Windows to prevent Explorer to crash RT when parallel scanning e.g. a currently written image file) -FILE * safe_g_fopen_WriteBinLock(const Glib::ustring& fname) { - FILE* f=NULL; - -#ifdef WIN32 - // g_fopen just uses _wfopen internally on Windows, does not lock access and has no options to set this - // so use a native function to work around this problem - wchar_t *wFname = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); - HANDLE hFile = CreateFileW(wFname, GENERIC_READ | GENERIC_WRITE, 0 /* no sharing allowed */, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - g_free(wFname); - - if (hFile==INVALID_HANDLE_VALUE) - f=NULL; - else - f=_fdopen( _open_osfhandle((intptr_t)hFile, 0) , "wb"); -#else - f = safe_g_fopen(fname, "wb"); -#endif - - return f; -} - -// Covers old UNIX ::open, which expects ANSI instead of UTF8 on Windows -int safe_open_ReadOnly(const char *fname) { - int fd=-1; - -#ifdef WIN32 - // First convert UTF8 to UTF16, then use Windows function to open - wchar_t *wFname = (wchar_t*)g_utf8_to_utf16 (fname, -1, NULL, NULL, NULL); - HANDLE hFile = CreateFileW(wFname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - g_free(wFname); - - // convert back to old file descriptor format - if (hFile!=INVALID_HANDLE_VALUE) fd = _open_osfhandle((intptr_t)hFile, 0); -#else - fd = ::open(fname, O_RDONLY); -#endif - - return fd; -} - - -FILE * safe_g_fopen(const Glib::ustring& src,const gchar *mode) -{ - return g_fopen(src.c_str(),mode); -} - -bool safe_file_test (const Glib::ustring& filename, Glib::FileTest test) -{ - return Glib::file_test (filename, test); -} - -int safe_g_remove(const Glib::ustring& filename) -{ - return ::g_remove(filename.c_str()); -} - -int safe_g_rename(const Glib::ustring& oldFilename, const Glib::ustring& newFilename) -{ - return ::g_rename(oldFilename.c_str(), newFilename.c_str()); -} - -int safe_g_mkdir_with_parents(const Glib::ustring& dirName, int mode) -{ - return ::g_mkdir_with_parents(dirName.c_str(), mode); -} - -Glib::ustring safe_get_user_picture_dir() { - #ifdef WIN32 - // get_user_special_dir/pictures crashes on some Windows configurations. - // so we use the safe native functions here - WCHAR pathW[MAX_PATH]={0}; - if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_MYPICTURES,false)) { - char pathA[MAX_PATH]; - WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); - return Glib::ustring(pathA); - } else return Glib::ustring("C:\\"); - - #else - - return Glib::get_user_special_dir (G_USER_DIRECTORY_PICTURES); - - #endif -} - -Glib::ustring safe_get_user_home_dir() { - #ifdef WIN32 - // get_user_special_dir/pictures crashes on some Windows configurations. - // so we use the safe native functions here - WCHAR pathW[MAX_PATH]={0}; - if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_PERSONAL,false)) { - char pathA[MAX_PATH]; - WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); - return Glib::ustring(pathA); - } else return Glib::ustring("C:\\"); - - #else - - return Glib::get_home_dir(); - - #endif -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2010 Sasha Vasko + * Copyright (c) 2010 Oliver Duis + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ -#ifdef WIN32 -Glib::ustring safe_get_user_profile_dir() { - WCHAR pathW[MAX_PATH]={0}; - if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_PROFILE,false)) { - char pathA[MAX_PATH]; - WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); - return Glib::ustring(pathA); - } else return Glib::ustring("C:\\"); -} -#endif +#include "safegtk.h" +#include "../rtgui/guiutils.h" +#include +#include +#ifdef WIN32 +#include +// for GCC32 +#ifndef _WIN32_IE +#define _WIN32_IE 0x0600 +#endif +#include +#include +#else +#include +#endif +#include "../rtgui/rtimage.h" +#include - -Glib::ustring safe_get_user_desktop_dir() { - #ifdef WIN32 - // get_user_special_dir/pictures crashes on some Windows configurations. - // so we use the safe native functions here - WCHAR pathW[MAX_PATH]={0}; - if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_DESKTOP,false)) { - char pathA[MAX_PATH]; - WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); - return Glib::ustring(pathA); - } else return Glib::ustring("C:\\"); - - #else - - return Glib::get_user_special_dir (G_USER_DIRECTORY_DESKTOP); - - #endif -} - -#ifdef WIN32 -/* - * Test if the path is a root path based on the content of the string - * - * Warning: this function is a workaround for Windows platform, and not necessarily bullet proof - */ + +Glib::RefPtr safe_create_from_file(const Glib::ustring& filename) +{ + Glib::RefPtr res; + Glib::ustring path = RTImage::findIconAbsolutePath(filename); + if (path.length()) { + try { + res = Gdk::Pixbuf::create_from_file (path); + } + catch (Glib::Exception& ex) { + printf ("ERROR: (ustring) File \"%s\" not found.\n", ex.what().c_str()); + } + } + return res; +} + +Cairo::RefPtr safe_create_from_png(const Glib::ustring& filename) +{ + Cairo::RefPtr res; + Glib::ustring path = RTImage::findIconAbsolutePath(filename); + if (path.length()) { + // files_test need a std::string which (as stated in its proto) but will only work if + // we use the Glib::ustring filename !? + try { + // create_from_png need a std::string converted from UTF8 with safe_locale_from_utf8 + res = Cairo::ImageSurface::create_from_png (safe_locale_from_utf8(path)); + } catch (...) { + printf("ERROR: (ustring) File \"%s\" not found.\n", path.c_str()); + } + } + return res; +} + +Glib::RefPtr safe_query_file_info (Glib::RefPtr &file) +{ + Glib::RefPtr info; +#ifdef GLIBMM_EXCEPTIONS_ENABLED + try { info = file->query_info(); }catch (...) { } +#else + std::auto_ptr error; + info = file->query_info("*", Gio::FILE_QUERY_INFO_NONE, error); +#endif + return info; +} + +Glib::RefPtr safe_next_file (Glib::RefPtr &dirList) +{ + Glib::RefPtr info; +#ifdef GLIBMM_EXCEPTIONS_ENABLED + bool retry; + Glib::ustring last_error = ""; + do { + retry = false; + try { + info = dirList->next_file(); + } catch (Glib::Exception& ex) { + printf ("%s\n", ex.what().c_str()); + // API problem: not possible to differ between error looking at particular entry or + // general error scanning the directory. We do a hack by retrying and see if the + // error changes, if it does we can assume it's about the current filename and we + // should look at the next. More likely if a single file error is that the next + // retry is okay of course. + retry = (ex.what() != last_error); + last_error = ex.what(); + } + } while (retry); +#else + bool retry; + Glib::ustring last_error = ""; + do { + retry = false; + std::auto_ptr error; + Glib::RefPtr cancellable; + info = dirList->next_file(cancellable, error); + if (!info && error.get()) { + printf ("%s\n", error.what().c_str()); + retry = (error.what() != last_error); + last_error = error.what(); + } + } while (retry); +#endif + return info; +} + +#ifdef GLIBMM_EXCEPTIONS_ENABLED +# define SAFE_ENUMERATOR_CODE_START \ + do{try { if ((dirList = dir->enumerate_children ())) \ + for (Glib::RefPtr info = safe_next_file(dirList); info; info = safe_next_file(dirList)) { + +# define SAFE_ENUMERATOR_CODE_END \ + }} catch (Glib::Exception& ex) { printf ("%s\n", ex.what().c_str()); }}while(0) +#else +# define SAFE_ENUMERATOR_CODE_START \ + do{std::auto_ptr error; Glib::RefPtr cancellable; \ + if ((dirList = dir->enumerate_children (cancellable, "*", Gio::FILE_QUERY_INFO_NONE, error))) \ + for (Glib::RefPtr info = safe_next_file(dirList); info; info = safe_next_file(dirList)) { + +# define SAFE_ENUMERATOR_CODE_END } if (error.get()) printf ("%s\n", error->what().c_str());}while (0) +#endif + +#ifdef WIN32 + +// High speed Windows version +void safe_build_file_list (Glib::RefPtr &dir, std::vector &flist) +{ + Glib::ustring fullPath=dir->get_path() + Glib::ustring("\\*"); + + DWORD dwVersion=GetVersion(); + bool win7Plus=(LOBYTE(LOWORD(dwVersion))>6) || ((LOBYTE(LOWORD(dwVersion))==6) && HIBYTE(LOWORD(dwVersion))>=1); // 6.1 or better + + wchar_t *wDirName = (wchar_t*)g_utf8_to_utf16 (fullPath.c_str(), -1, NULL, NULL, NULL); + WIN32_FIND_DATAW fi; + + HANDLE hFF=FindFirstFileExW(wDirName, + //win7Plus ? FindExInfoBasic : // TODO: Add if MinGW is updated, makes it even faster + FindExInfoStandard,&fi, + FindExSearchNameMatch,NULL, + win7Plus ? 2 : 0); // Win7 large fetch + + if (hFF != INVALID_HANDLE_VALUE) { + do { + SYSTEMTIME stUTC; + FileTimeToSystemTime(&fi.ftLastWriteTime, &stUTC); + char time[64]; + sprintf(time,"%d-%02d-%02dT%02d:%02d:%02dZ",stUTC.wYear,stUTC.wMonth,stUTC.wDay,stUTC.wHour,stUTC.wMinute,stUTC.wSecond); + Glib::TimeVal timeVal; + timeVal.assign_from_iso8601(Glib::ustring(time)); + + char pathA[MAX_PATH]; + WideCharToMultiByte(CP_UTF8,0,(WCHAR*)fi.cFileName,-1,pathA,MAX_PATH,0,0); + flist.push_back (FileMTimeInfo (removeExtension(Glib::ustring(pathA)), timeVal)); + + } while (FindNextFileW(hFF, &fi)); + + FindClose(hFF); + } + + g_free(wDirName); +} +#else + +// Generic file list build +void safe_build_file_list (Glib::RefPtr &dir, std::vector &flist) +{ + Glib::RefPtr dirList; + if (dir) { + SAFE_ENUMERATOR_CODE_START + flist.push_back (FileMTimeInfo (removeExtension(info->get_name()), info->modification_time())); + SAFE_ENUMERATOR_CODE_END; + } +} +#endif +/* + * safe_build_file_list can now filter out at the source all files that doesn't have the extensions specified (if provided) + */ +void safe_build_file_list (Glib::RefPtr &dir, std::vector &names, const Glib::ustring &directory, const std::vector *extensions) +{ + Glib::RefPtr dirList; + + if (dir) { + if (!extensions) { + SAFE_ENUMERATOR_CODE_START + names.push_back (Glib::build_filename (directory, info->get_name())); + SAFE_ENUMERATOR_CODE_END; + } + else { + // convert extensions to lowercase in a new vector list + std::vector lcExtensions; + for (unsigned int i=0; isize(); i++) + lcExtensions.push_back ((*extensions)[i].lowercase()); + + SAFE_ENUMERATOR_CODE_START + // convert the current filename to lowercase in a new ustring + Glib::ustring fname = Glib::ustring(info->get_name()).lowercase(); + + size_t pos = fname.find_last_of('.'); + if (pos < (fname.length()-1)) { + // there is an extension to the filename + + Glib::ustring lcFileExt = fname.substr(pos+1).lowercase(); + + // look out if it has one of the retained extensions + for (size_t i=0; iget_name())); + break; + } + } + } + SAFE_ENUMERATOR_CODE_END; + } + } +} + + +void safe_build_subdir_list (Glib::RefPtr &dir, std::vector &subDirs, bool add_hidden) +{ + Glib::RefPtr dirList; + if (dir) + { + // CD-ROMs with no drive inserted are reported, but do not exist, causing RT to crash + if (!safe_file_test(dir->get_path(),Glib::FILE_TEST_EXISTS)) return; + + SAFE_ENUMERATOR_CODE_START + if (info->get_file_type() == Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || add_hidden)) + subDirs.push_back (info->get_name()); + SAFE_ENUMERATOR_CODE_END; + } +} + +/* + * For an unknown reason, Glib::filename_to_utf8 doesn't work on Windows, so we're using + * Glib::filename_to_utf8 for Linux/Apple and Glib::locale_to_utf8 for Windows + */ +Glib::ustring safe_filename_to_utf8 (const std::string& src) +{ + Glib::ustring utf8_str; +#ifdef WIN32 +#ifdef GLIBMM_EXCEPTIONS_ENABLED + try { + utf8_str = Glib::locale_to_utf8(src); + } + catch (const Glib::Error& e) { + utf8_str = Glib::convert_with_fallback(src, "UTF-8", "ISO-8859-1","?"); + } +#else + { + std::auto_ptr error; + utf8_str = locale_to_utf8(src, error); + if (error.get()) + utf8_str = Glib::convert_with_fallback(src, "UTF-8", "ISO-8859-1","?", error); + } +#endif //GLIBMM_EXCEPTIONS_ENABLED +#else + utf8_str = Glib::filename_to_utf8(src); +#endif + return utf8_str; +} + +Glib::ustring safe_locale_to_utf8 (const std::string& src) +{ + Glib::ustring utf8_str; +#ifdef GLIBMM_EXCEPTIONS_ENABLED + try { + utf8_str = Glib::locale_to_utf8(src); + } + catch (const Glib::Error& e) { + utf8_str = Glib::convert_with_fallback(src, "UTF-8", "ISO-8859-1","?"); + } +#else + { + std::auto_ptr error; + utf8_str = locale_to_utf8(src, error); + if (error.get()) + utf8_str = Glib::convert_with_fallback(src, "UTF-8", "ISO-8859-1","?", error); + } +#endif //GLIBMM_EXCEPTIONS_ENABLED + return utf8_str; +} + +std::string safe_locale_from_utf8 (const Glib::ustring& utf8_str) +{ + std::string str; +#ifdef GLIBMM_EXCEPTIONS_ENABLED + try { + str = Glib::locale_from_utf8(utf8_str); + } + catch (const Glib::Error& e) { + //str = Glib::convert_with_fallback(utf8_str, "ISO-8859-1", "UTF-8", "?"); + } +#else + { + std::auto_ptr error; + str = Glib::locale_from_utf8(utf8_str, error); + /*if (error.get()) + {str = Glib::convert_with_fallback(utf8_str, "ISO-8859-1", "UTF-8", "?", error);}*/ + } +#endif //GLIBMM_EXCEPTIONS_ENABLED + return str; +} + +bool safe_spawn_command_line_async (const Glib::ustring& cmd_utf8) +{ + std::string cmd; + bool success = false; +#ifdef GLIBMM_EXCEPTIONS_ENABLED + try { + cmd = Glib::filename_from_utf8(cmd_utf8); + printf ("command line: %s\n", cmd.c_str()); + Glib::spawn_command_line_async (cmd.c_str()); + success = true; + } catch (Glib::Exception& ex) { + printf ("%s\n", ex.what().c_str()); + } +#else + std::auto_ptr error; + cmd = Glib::filename_from_utf8(cmd_utf8, error); + if (!error.get()) { + printf ("command line: %s\n", cmd.c_str()); + Glib::spawn_command_line_async (cmd, error); + } + if (error.get()) + printf ("%s\n", error->what().c_str()); + else + success = true; +#endif + return success; +} + +bool safe_spawn_command_line_sync (const Glib::ustring& cmd_utf8) +{ + int exitStatus=-1; + try { + //cmd = Glib::filename_from_utf8(cmd_utf8); + printf ("command line: %s\n", cmd_utf8.c_str()); + + // if it crashes here on windows, make sure you have the GTK runtime files gspawn-win32-helper*.exe files in RT directory + Glib::spawn_command_line_sync (cmd_utf8, NULL, NULL, &exitStatus); + } catch (Glib::Exception& ex) { + printf ("%s\n", ex.what().c_str()); + } + return (exitStatus==0); +} + +// Opens a file for binary writing and request exclusive lock (cases were you need "wb" mode plus locking) +// (Important on Windows to prevent Explorer to crash RT when parallel scanning e.g. a currently written image file) +FILE * safe_g_fopen_WriteBinLock(const Glib::ustring& fname) { + FILE* f=NULL; + +#ifdef WIN32 + // g_fopen just uses _wfopen internally on Windows, does not lock access and has no options to set this + // so use a native function to work around this problem + wchar_t *wFname = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); + HANDLE hFile = CreateFileW(wFname, GENERIC_READ | GENERIC_WRITE, 0 /* no sharing allowed */, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + g_free(wFname); + + if (hFile==INVALID_HANDLE_VALUE) + f=NULL; + else + f=_fdopen( _open_osfhandle((intptr_t)hFile, 0) , "wb"); +#else + f = safe_g_fopen(fname, "wb"); +#endif + + return f; +} + +// Covers old UNIX ::open, which expects ANSI instead of UTF8 on Windows +int safe_open_ReadOnly(const char *fname) { + int fd=-1; + +#ifdef WIN32 + // First convert UTF8 to UTF16, then use Windows function to open + wchar_t *wFname = (wchar_t*)g_utf8_to_utf16 (fname, -1, NULL, NULL, NULL); + HANDLE hFile = CreateFileW(wFname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + g_free(wFname); + + // convert back to old file descriptor format + if (hFile!=INVALID_HANDLE_VALUE) fd = _open_osfhandle((intptr_t)hFile, 0); +#else + fd = ::open(fname, O_RDONLY); +#endif + + return fd; +} + + +FILE * safe_g_fopen(const Glib::ustring& src,const gchar *mode) +{ + return g_fopen(src.c_str(),mode); +} + +bool safe_file_test (const Glib::ustring& filename, Glib::FileTest test) +{ + return Glib::file_test (filename, test); +} + +int safe_g_remove(const Glib::ustring& filename) +{ + return ::g_remove(filename.c_str()); +} + +int safe_g_rename(const Glib::ustring& oldFilename, const Glib::ustring& newFilename) +{ + return ::g_rename(oldFilename.c_str(), newFilename.c_str()); +} + +int safe_g_mkdir_with_parents(const Glib::ustring& dirName, int mode) +{ + return ::g_mkdir_with_parents(dirName.c_str(), mode); +} + +Glib::ustring safe_get_user_picture_dir() { + #ifdef WIN32 + // get_user_special_dir/pictures crashes on some Windows configurations. + // so we use the safe native functions here + WCHAR pathW[MAX_PATH]={0}; + if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_MYPICTURES,false)) { + char pathA[MAX_PATH]; + WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); + return Glib::ustring(pathA); + } else return Glib::ustring("C:\\"); + + #else + + return Glib::get_user_special_dir (G_USER_DIRECTORY_PICTURES); + + #endif +} + +Glib::ustring safe_get_user_home_dir() { + #ifdef WIN32 + // get_user_special_dir/pictures crashes on some Windows configurations. + // so we use the safe native functions here + WCHAR pathW[MAX_PATH]={0}; + if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_PERSONAL,false)) { + char pathA[MAX_PATH]; + WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); + return Glib::ustring(pathA); + } else return Glib::ustring("C:\\"); + + #else + + return Glib::get_home_dir(); + + #endif +} + +#ifdef WIN32 +Glib::ustring safe_get_user_profile_dir() { + WCHAR pathW[MAX_PATH]={0}; + if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_PROFILE,false)) { + char pathA[MAX_PATH]; + WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); + return Glib::ustring(pathA); + } else return Glib::ustring("C:\\"); +} +#endif + + +Glib::ustring safe_get_user_desktop_dir() { + #ifdef WIN32 + // get_user_special_dir/pictures crashes on some Windows configurations. + // so we use the safe native functions here + WCHAR pathW[MAX_PATH]={0}; + if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_DESKTOP,false)) { + char pathA[MAX_PATH]; + WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); + return Glib::ustring(pathA); + } else return Glib::ustring("C:\\"); + + #else + + return Glib::get_user_special_dir (G_USER_DIRECTORY_DESKTOP); + + #endif +} + +#ifdef WIN32 +/* + * Test if the path is a root path based on the content of the string + * + * Warning: this function is a workaround for Windows platform, and not necessarily bullet proof + */ bool safe_is_shortcut_dir (const Glib::ustring& path) { - return PathIsRootA(path.c_str()) || safe_get_user_home_dir() == path || safe_get_user_desktop_dir() == path || safe_get_user_profile_dir() == path; // || safe_get_user_picture_dir() == path; -} -#endif + return PathIsRootA(path.c_str()) || safe_get_user_home_dir() == path || safe_get_user_desktop_dir() == path || safe_get_user_profile_dir() == path; // || safe_get_user_picture_dir() == path; +} +#endif diff --git a/rtengine/safegtk.h b/rtengine/safegtk.h index eb10b7c5b..599a2e06d 100644 --- a/rtengine/safegtk.h +++ b/rtengine/safegtk.h @@ -1,52 +1,52 @@ -#ifndef SAFE_GTK_H_INCLUDED -#define SAFE_GTK_H_INCLUDED - -#include -#include -#include - -Glib::RefPtr safe_create_from_file(const Glib::ustring& filename); -Cairo::RefPtr safe_create_from_png(const Glib::ustring& filename); - -class FileMTimeInfo { - - public: - Glib::ustring fname; - Glib::TimeVal mtime; - - FileMTimeInfo (Glib::ustring name, Glib::TimeVal mtime) : fname(name), mtime(mtime) {} - bool operator<(const FileMTimeInfo& other) const { return mtime safe_query_file_info (Glib::RefPtr &file); -void safe_build_file_list (Glib::RefPtr &dir, std::vector &flist); -void safe_build_file_list (Glib::RefPtr &dir, std::vector &names, const Glib::ustring &directory = "", const std::vector *extensions=NULL); -void safe_build_subdir_list (Glib::RefPtr &dir, std::vector &subDirs, bool add_hidden); - -bool safe_spawn_command_line_async (const Glib::ustring& cmd_utf8); -bool safe_spawn_command_line_sync (const Glib::ustring& cmd_utf8); - -Glib::ustring safe_filename_to_utf8 (const std::string& src); -Glib::ustring safe_locale_to_utf8 (const std::string& src); // from rtengine -std::string safe_locale_from_utf8 (const Glib::ustring& utf8_str); -std::string safe_filename_from_utf8 (const Glib::ustring& utf8_str); - -FILE * safe_g_fopen(const Glib::ustring& src,const gchar *mode); -FILE * safe_g_fopen_WriteBinLock(const Glib::ustring& fname); -int safe_open_ReadOnly(const char *fname); - -bool safe_file_test (const Glib::ustring& filename, Glib::FileTest test); -int safe_g_remove(const Glib::ustring& filename); -int safe_g_rename(const Glib::ustring& oldFilename, const Glib::ustring& newFilename); -int safe_g_mkdir_with_parents(const Glib::ustring& dirName, int mode); - -Glib::ustring safe_get_user_picture_dir(); -Glib::ustring safe_get_user_home_dir(); -Glib::ustring safe_get_user_desktop_dir(); - +#ifndef SAFE_GTK_H_INCLUDED +#define SAFE_GTK_H_INCLUDED + +#include +#include +#include + +Glib::RefPtr safe_create_from_file(const Glib::ustring& filename); +Cairo::RefPtr safe_create_from_png(const Glib::ustring& filename); + +class FileMTimeInfo { + + public: + Glib::ustring fname; + Glib::TimeVal mtime; + + FileMTimeInfo (Glib::ustring name, Glib::TimeVal mtime) : fname(name), mtime(mtime) {} + bool operator<(const FileMTimeInfo& other) const { return mtime safe_query_file_info (Glib::RefPtr &file); +void safe_build_file_list (Glib::RefPtr &dir, std::vector &flist); +void safe_build_file_list (Glib::RefPtr &dir, std::vector &names, const Glib::ustring &directory = "", const std::vector *extensions=NULL); +void safe_build_subdir_list (Glib::RefPtr &dir, std::vector &subDirs, bool add_hidden); + +bool safe_spawn_command_line_async (const Glib::ustring& cmd_utf8); +bool safe_spawn_command_line_sync (const Glib::ustring& cmd_utf8); + +Glib::ustring safe_filename_to_utf8 (const std::string& src); +Glib::ustring safe_locale_to_utf8 (const std::string& src); // from rtengine +std::string safe_locale_from_utf8 (const Glib::ustring& utf8_str); +std::string safe_filename_from_utf8 (const Glib::ustring& utf8_str); + +FILE * safe_g_fopen(const Glib::ustring& src,const gchar *mode); +FILE * safe_g_fopen_WriteBinLock(const Glib::ustring& fname); +int safe_open_ReadOnly(const char *fname); + +bool safe_file_test (const Glib::ustring& filename, Glib::FileTest test); +int safe_g_remove(const Glib::ustring& filename); +int safe_g_rename(const Glib::ustring& oldFilename, const Glib::ustring& newFilename); +int safe_g_mkdir_with_parents(const Glib::ustring& dirName, int mode); + +Glib::ustring safe_get_user_picture_dir(); +Glib::ustring safe_get_user_home_dir(); +Glib::ustring safe_get_user_desktop_dir(); + #ifdef WIN32 -Glib::ustring safe_get_user_profile_dir(); -bool safe_is_shortcut_dir (const Glib::ustring& filename); -#endif - -#endif +Glib::ustring safe_get_user_profile_dir(); +bool safe_is_shortcut_dir (const Glib::ustring& filename); +#endif + +#endif diff --git a/rtengine/sleefsseavx.c b/rtengine/sleefsseavx.c index 543cf5abc..6b83c859a 100644 --- a/rtengine/sleefsseavx.c +++ b/rtengine/sleefsseavx.c @@ -1,6 +1,6 @@ -#ifndef SLEEFSSEAVX -#define SLEEFSSEAVX - +#ifndef SLEEFSSEAVX +#define SLEEFSSEAVX + #include #include //#include @@ -1222,7 +1222,7 @@ static INLINE vfloat xlogf(vfloat d) { return x; } - + static INLINE vfloat xlogf0(vfloat d) { vfloat x, x2, t, m; vint2 e; @@ -1247,7 +1247,7 @@ static INLINE vfloat xlogf0(vfloat d) { return x; } - + static INLINE vfloat xexpf(vfloat d) { vint2 q = vrint_vi2_vf(vmulf(d, vcast_vf_f(R_LN2f))); @@ -1267,7 +1267,7 @@ static INLINE vfloat xexpf(vfloat d) { u = vldexpf(u, q); u = vself(vmaskf_isminf(d), vcast_vf_f(0.0f), u); -// -104.0 +// -104.0 u = vself(vmaskf_gt(vcast_vf_f(-104), d), vcast_vf_f(0), u); return u; } @@ -1315,12 +1315,12 @@ static INLINE vfloat SQRV(vfloat a){ return _mm_mul_ps( a,a ); } -static inline void vswap( vmask condition, vfloat &a, vfloat &b) { - vfloat temp = vself(condition, a, b); // the larger of the two - condition = vnotm(condition); // invert the mask - a = vself(condition, a, b); // the smaller of the two - b = temp; +static inline void vswap( vmask condition, vfloat &a, vfloat &b) { + vfloat temp = vself(condition, a, b); // the larger of the two + condition = vnotm(condition); // invert the mask + a = vself(condition, a, b); // the smaller of the two + b = temp; } #endif // __SSE2__ -#endif // SLEEFSSEAVX +#endif // SLEEFSSEAVX diff --git a/rtengine/sleefsseavx.h b/rtengine/sleefsseavx.h index b2b179dd3..2058c3749 100644 --- a/rtengine/sleefsseavx.h +++ b/rtengine/sleefsseavx.h @@ -10,7 +10,7 @@ typedef __m128i vint; typedef __m128 vfloat; typedef __m128i vint2; -typedef __m128i vmask; +typedef __m128i vmask; static vdouble vloadu(double *p) { return _mm_loadu_pd(p); } static void vstoreu(double *p, vdouble v) { _mm_storeu_pd(p, v); } @@ -27,7 +27,7 @@ static void vstoreui2(int32_t *p, vint2 v) { _mm_storeu_si128((__m128i *)p, (__m #define VECTLENSP 8 typedef __m256d vdouble; -typedef __m128i vint; +typedef __m128i vint; typedef __m256 vfloat; @@ -102,7 +102,7 @@ vfloat xasinf(vfloat s); vfloat xacosf(vfloat s); vfloat xatanf(vfloat s); vfloat xatan2f(vfloat y, vfloat x); -vfloat xlogf(vfloat d); +vfloat xlogf(vfloat d); vfloat xlogf0(vfloat d); vfloat xexpf(vfloat d); vfloat xcbrtf(vfloat s); diff --git a/rtengine/slicer.cc b/rtengine/slicer.cc index 5008ee1f1..c4a5d09e1 100644 --- a/rtengine/slicer.cc +++ b/rtengine/slicer.cc @@ -1,138 +1,138 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include #include #include "rt_math.h" #include "slicer.h" -#ifdef _OPENMP -#include -#endif +#ifdef _OPENMP +#include +#endif using namespace std; - -// If no parameter set, everything = 0 -> process all the image -Block::Block() { - posX = 0; - posY = 0; - width = 0; - height = 0; -} - -Block::Block(unsigned int x, unsigned int y, unsigned int w, unsigned int h) { - posX = x; - posY = y; - width = w; - height = h; -} - -/* - * Slice a sub-region to process in blocks who's size is given by the number of processor - * and the number of pixel per block (and hence the memory footprint) - */ -Slicer::Slicer(unsigned int imageWidth, unsigned int imageHeight, Block *subRegion, unsigned int pixels ) { - // If the sub-region has a portrait shape, X and Y coordinates are swapped for better result - // It will be swapped back when sending back the block coordinates - region.width = !(subRegion->width) ? imageWidth : subRegion->width; - region.height = !(subRegion->height) ? imageHeight : subRegion->height; // Assuming that the sub-region is under posY - if (region.width < region.height) { - region.width = !(subRegion->height) ? imageHeight : subRegion->height; - region.height = !(subRegion->width) ? imageWidth : subRegion->width; // Assuming that the sub-region is under posY - portrait = true; - imWidth = imageHeight; - imHeight = imageWidth; - region.posX = subRegion->posY; - region.posY = subRegion->posX; - } - else { - portrait = false; - imWidth = imageWidth; - imHeight = imageHeight; - region.posX = subRegion->posX; - region.posY = subRegion->posY; - } - double subRegionRatio = (double)(region.width) / (double)(region.height); - - //total number of core/processor -#ifdef _OPENMP - unsigned int procNumber = omp_get_num_procs(); -#else - unsigned int procNumber = 1; -#endif - - //calculate the number of block - blockNumber = (double(region.width*region.height) / (double)pixels); - blockNumber = int((rtengine::max(blockNumber, 1U) + (double)procNumber/2.)/procNumber)*procNumber; - vBlockNumber = (unsigned int)(sqrt((double)blockNumber / subRegionRatio)+0.5); - vBlockNumber = CLAMP(vBlockNumber, 1, blockNumber); - hBlockNumber = (double)blockNumber / (double)vBlockNumber; - blockWidth = 1.0 / hBlockNumber; - - double maxPixelNumberX = (double)region.height / (double)vBlockNumber; - double maxPixelNumberY = (double)region.width / (double)((unsigned int)hBlockNumber); - if (maxPixelNumberX - (double)((unsigned int)maxPixelNumberX) != 0.) maxPixelNumberX += 1.; - if (maxPixelNumberY - (double)((unsigned int)maxPixelNumberY) != 0.) maxPixelNumberY += 1.; - maxPixelNumber = (unsigned int)maxPixelNumberX * (unsigned int)maxPixelNumberY; - -} - -// return the absolute position and size of the requested block -void Slicer::get_block(unsigned int numBlock, Block *block) { - double roundingTradeOff = (hBlockNumber - (double)((int)hBlockNumber)) == 0.5 ? 2.1 : 2.0; - unsigned int alreadyCompletedLineNbr = (unsigned int)((double)(numBlock) * blockWidth + (blockWidth/roundingTradeOff)); - - unsigned int prevLineEnd = (unsigned int)((double)alreadyCompletedLineNbr * hBlockNumber + 0.5); - unsigned int myLineEnd = (unsigned int)((double)(alreadyCompletedLineNbr+1) * hBlockNumber + 0.5); - - unsigned int nbrCellsOnMyLine = myLineEnd - prevLineEnd; - unsigned int cellOnMyLine = numBlock - prevLineEnd; - - unsigned int blockStart = (unsigned int)(((double)region.width / (double)nbrCellsOnMyLine)*(double)(cellOnMyLine)); - unsigned int blockEnd = (unsigned int)(((double)region.width / (double)nbrCellsOnMyLine)*(double)(cellOnMyLine+1)); - block->width = blockEnd - blockStart; - block->posX = region.posX + blockStart; - if (cellOnMyLine == (nbrCellsOnMyLine-1)) { - // We make sure that the last block of the row take the rest of the remaining X space - block->width = region.posX + region.width - block->posX; - } - - blockStart = (unsigned int)(((double)region.height / (double)vBlockNumber)*(double)(alreadyCompletedLineNbr)); - blockEnd = (unsigned int)(((double)region.height / (double)vBlockNumber)*(double)(alreadyCompletedLineNbr+1)); - block->height = blockEnd - blockStart; - block->posY = region.posY + blockStart; - if (alreadyCompletedLineNbr == (vBlockNumber-1)) { - block->height = region.posY + region.height - block->posY; - } - - if (portrait) { - // we swap back the X/Y coordinates - unsigned int temp; - - temp = block->posX; - block->posX = block->posY; - block->posY = temp; - - temp = block->width; - block->width = block->height; - block->height = temp; - - } -} + +// If no parameter set, everything = 0 -> process all the image +Block::Block() { + posX = 0; + posY = 0; + width = 0; + height = 0; +} + +Block::Block(unsigned int x, unsigned int y, unsigned int w, unsigned int h) { + posX = x; + posY = y; + width = w; + height = h; +} + +/* + * Slice a sub-region to process in blocks who's size is given by the number of processor + * and the number of pixel per block (and hence the memory footprint) + */ +Slicer::Slicer(unsigned int imageWidth, unsigned int imageHeight, Block *subRegion, unsigned int pixels ) { + // If the sub-region has a portrait shape, X and Y coordinates are swapped for better result + // It will be swapped back when sending back the block coordinates + region.width = !(subRegion->width) ? imageWidth : subRegion->width; + region.height = !(subRegion->height) ? imageHeight : subRegion->height; // Assuming that the sub-region is under posY + if (region.width < region.height) { + region.width = !(subRegion->height) ? imageHeight : subRegion->height; + region.height = !(subRegion->width) ? imageWidth : subRegion->width; // Assuming that the sub-region is under posY + portrait = true; + imWidth = imageHeight; + imHeight = imageWidth; + region.posX = subRegion->posY; + region.posY = subRegion->posX; + } + else { + portrait = false; + imWidth = imageWidth; + imHeight = imageHeight; + region.posX = subRegion->posX; + region.posY = subRegion->posY; + } + double subRegionRatio = (double)(region.width) / (double)(region.height); + + //total number of core/processor +#ifdef _OPENMP + unsigned int procNumber = omp_get_num_procs(); +#else + unsigned int procNumber = 1; +#endif + + //calculate the number of block + blockNumber = (double(region.width*region.height) / (double)pixels); + blockNumber = int((rtengine::max(blockNumber, 1U) + (double)procNumber/2.)/procNumber)*procNumber; + vBlockNumber = (unsigned int)(sqrt((double)blockNumber / subRegionRatio)+0.5); + vBlockNumber = CLAMP(vBlockNumber, 1, blockNumber); + hBlockNumber = (double)blockNumber / (double)vBlockNumber; + blockWidth = 1.0 / hBlockNumber; + + double maxPixelNumberX = (double)region.height / (double)vBlockNumber; + double maxPixelNumberY = (double)region.width / (double)((unsigned int)hBlockNumber); + if (maxPixelNumberX - (double)((unsigned int)maxPixelNumberX) != 0.) maxPixelNumberX += 1.; + if (maxPixelNumberY - (double)((unsigned int)maxPixelNumberY) != 0.) maxPixelNumberY += 1.; + maxPixelNumber = (unsigned int)maxPixelNumberX * (unsigned int)maxPixelNumberY; + +} + +// return the absolute position and size of the requested block +void Slicer::get_block(unsigned int numBlock, Block *block) { + double roundingTradeOff = (hBlockNumber - (double)((int)hBlockNumber)) == 0.5 ? 2.1 : 2.0; + unsigned int alreadyCompletedLineNbr = (unsigned int)((double)(numBlock) * blockWidth + (blockWidth/roundingTradeOff)); + + unsigned int prevLineEnd = (unsigned int)((double)alreadyCompletedLineNbr * hBlockNumber + 0.5); + unsigned int myLineEnd = (unsigned int)((double)(alreadyCompletedLineNbr+1) * hBlockNumber + 0.5); + + unsigned int nbrCellsOnMyLine = myLineEnd - prevLineEnd; + unsigned int cellOnMyLine = numBlock - prevLineEnd; + + unsigned int blockStart = (unsigned int)(((double)region.width / (double)nbrCellsOnMyLine)*(double)(cellOnMyLine)); + unsigned int blockEnd = (unsigned int)(((double)region.width / (double)nbrCellsOnMyLine)*(double)(cellOnMyLine+1)); + block->width = blockEnd - blockStart; + block->posX = region.posX + blockStart; + if (cellOnMyLine == (nbrCellsOnMyLine-1)) { + // We make sure that the last block of the row take the rest of the remaining X space + block->width = region.posX + region.width - block->posX; + } + + blockStart = (unsigned int)(((double)region.height / (double)vBlockNumber)*(double)(alreadyCompletedLineNbr)); + blockEnd = (unsigned int)(((double)region.height / (double)vBlockNumber)*(double)(alreadyCompletedLineNbr+1)); + block->height = blockEnd - blockStart; + block->posY = region.posY + blockStart; + if (alreadyCompletedLineNbr == (vBlockNumber-1)) { + block->height = region.posY + region.height - block->posY; + } + + if (portrait) { + // we swap back the X/Y coordinates + unsigned int temp; + + temp = block->posX; + block->posX = block->posY; + block->posY = temp; + + temp = block->width; + block->width = block->height; + block->height = temp; + + } +} diff --git a/rtengine/slicer.h b/rtengine/slicer.h index ac27bca82..5cf24ddd0 100644 --- a/rtengine/slicer.h +++ b/rtengine/slicer.h @@ -1,61 +1,61 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _SLICER_ -#define _SLICER_ - -//The image is divided in blocks even on single processor machine, mainly to decrease memory consumption -//maximum number of pixel per block -#define PIXELS_PER_BLOCK 250000 - -/* +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _SLICER_ +#define _SLICER_ + +//The image is divided in blocks even on single processor machine, mainly to decrease memory consumption +//maximum number of pixel per block +#define PIXELS_PER_BLOCK 250000 + +/* * Used to specify a subregion of an image and to specify a cell in this subregion - */ -class Block { - public: - unsigned int posX; - unsigned int posY; - unsigned int width; // If 0, use the full width of the image - unsigned int height; // If 0, use the full height of the image - Block(); - Block(unsigned int x, unsigned int y, unsigned int w, unsigned int h); -}; - -/* - * This class handle the best slicing of the image with a given number of pixels per block and the number of - * processor, and tries to create blocks as square as possible. There can be a different number of block on + */ +class Block { + public: + unsigned int posX; + unsigned int posY; + unsigned int width; // If 0, use the full width of the image + unsigned int height; // If 0, use the full height of the image + Block(); + Block(unsigned int x, unsigned int y, unsigned int w, unsigned int h); +}; + +/* + * This class handle the best slicing of the image with a given number of pixels per block and the number of + * processor, and tries to create blocks as square as possible. There can be a different number of block on * each line, and the pixel per block requested may be oversized by very few percents. - */ -class Slicer { - protected: - bool portrait; // Orientation of the sub-region - unsigned int imWidth; // Image width - unsigned int imHeight; // Image height - Block region; // Sub-region to process - double hBlockNumber; // Horizontal number of block for the sub-region - unsigned int vBlockNumber; // Vertical number of block for the sub-region - double blockWidth; - - public: - unsigned int blockNumber; // number of block for the sub-region - unsigned int maxPixelNumber; // number of pixel of the biggest block (for memory allocation purpose) - Slicer(unsigned int imageWidth, unsigned int imageHeight, Block *subRegion, unsigned int pixels); - void get_block(unsigned int blockId, Block *block); -}; - -#endif + */ +class Slicer { + protected: + bool portrait; // Orientation of the sub-region + unsigned int imWidth; // Image width + unsigned int imHeight; // Image height + Block region; // Sub-region to process + double hBlockNumber; // Horizontal number of block for the sub-region + unsigned int vBlockNumber; // Vertical number of block for the sub-region + double blockWidth; + + public: + unsigned int blockNumber; // number of block for the sub-region + unsigned int maxPixelNumber; // number of pixel of the biggest block (for memory allocation purpose) + Slicer(unsigned int imageWidth, unsigned int imageHeight, Block *subRegion, unsigned int pixels); + void get_block(unsigned int blockId, Block *block); +}; + +#endif diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index 9701b9022..9130b0ba9 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -569,11 +569,11 @@ TagDirectoryTable::TagDirectoryTable (TagDirectory* p, unsigned char *v,int mems { values = new unsigned char[valuesSize]; memcpy(values,v,valuesSize); - - // Security ; will avoid to read above the buffer limit if the RT's tagDirectoryTable is longer that what's in the file - int count = valuesSize/getTypeSize(type); - - for(const TagAttrib* tattr = ta; tattr->ignore != -1 && tattr->IDignore != -1 && tattr->IDID*getTypeSize(type)), tattr->type == AUTO ? type : tattr->type); tags.push_back(newTag); // Here we can insert more tag in the same offset because of bitfield meaning } @@ -585,10 +585,10 @@ TagDirectoryTable::TagDirectoryTable (TagDirectory* p, FILE* f, int memsize,int values = new unsigned char[valuesSize]; fread (values, 1, valuesSize, f); - // Security ; will avoid to read above the buffer limit if the RT's tagDirectoryTable is longer that what's in the file - int count = valuesSize/getTypeSize(type); - - for(const TagAttrib* tattr = ta; tattr->ignore != -1 && tattr->IDignore != -1 && tattr->IDID*getTypeSize(type)), tattr->type == AUTO ? type : tattr->type); tags.push_back(newTag); // Here we can insert more tag in the same offset because of bitfield meaning } diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 216309c89..2c0c913d6 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -1,347 +1,347 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "batchqueuepanel.h" -#include "options.h" -#include "preferences.h" -#include "multilangmgr.h" -#include "rtwindow.h" -#include "soundman.h" -#include "../rtengine/safegtk.h" -#include "rtimage.h" - -struct BQProcessLoaded { - BatchQueue* bq; -}; - -int processLoadedBatchQueueUIThread (void* data) { - - BatchQueue* bq = static_cast(data); - bq->resizeLoadedQueue(); - return 0; -} - -static Glib::ustring makeFolderLabel(Glib::ustring path) -{ - if (!safe_file_test (path, Glib::FILE_TEST_IS_DIR)) - return "(" + M("GENERAL_NONE") + ")"; - if (path.size() > 40) { - size_t last_ds = path.find_last_of (G_DIR_SEPARATOR); - if (last_ds != Glib::ustring::npos && last_ds > 10) { - path = "..." + path.substr(last_ds); - } - } - return path; -} - -BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) { - - batchQueue = Gtk::manage( new BatchQueue(aFileCatalog) ); - - // construct batch queue panel with the extra "start" and "stop" button - Gtk::VBox* batchQueueButtonBox = Gtk::manage (new Gtk::VBox); - start = Gtk::manage (new Gtk::ToggleButton (M("FILEBROWSER_STARTPROCESSING"))); - stop = Gtk::manage (new Gtk::ToggleButton (M("FILEBROWSER_STOPPROCESSING"))); - autoStart = Gtk::manage (new Gtk::CheckButton (M("BATCHQUEUE_AUTOSTART"))); - start->set_tooltip_markup (M("FILEBROWSER_STARTPROCESSINGHINT")); - stop->set_tooltip_markup (M("FILEBROWSER_STOPPROCESSINGHINT")); - autoStart->set_tooltip_text (M("FILEBROWSER_TOOLTIP_STOPPROCESSING")); - start->set_active (false); - stop->set_active (true); - autoStart->set_active (options.procQueueEnabled); - - start->set_image (*Gtk::manage (new RTImage ("gtk-media-play.png"))); - startConnection = start->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::startBatchProc)); - stop->set_image (*Gtk::manage (new RTImage ("gtk-media-stop.png"))); - stopConnection = stop->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::stopBatchProc)); - batchQueueButtonBox->pack_start (*start, Gtk::PACK_SHRINK, 4); - batchQueueButtonBox->pack_start (*stop, Gtk::PACK_SHRINK, 4); - batchQueueButtonBox->pack_start (*autoStart, Gtk::PACK_SHRINK, 4); - - // Output directory selection - fdir = Gtk::manage (new Gtk::Frame (M("PREFERENCES_OUTDIR"))); - Gtk::VBox* odvb = Gtk::manage (new Gtk::VBox ()); - odvb->set_border_width (4); - Gtk::HBox* hb2 = Gtk::manage (new Gtk::HBox ()); - useTemplate = Gtk::manage (new Gtk::RadioButton (M("PREFERENCES_OUTDIRTEMPLATE")+":")); - hb2->pack_start (*useTemplate, Gtk::PACK_SHRINK,4); - outdirTemplate = Gtk::manage (new Gtk::Entry ()); - hb2->pack_start (*outdirTemplate); - odvb->pack_start (*hb2, Gtk::PACK_SHRINK, 4); - outdirTemplate->set_tooltip_markup (M("PREFERENCES_OUTDIRTEMPLATEHINT")); - useTemplate->set_tooltip_markup (M("PREFERENCES_OUTDIRTEMPLATEHINT")); - Gtk::HBox* hb3 = Gtk::manage (new Gtk::HBox ()); - useFolder = Gtk::manage (new Gtk::RadioButton (M("PREFERENCES_OUTDIRFOLDER")+":")); - hb3->pack_start (*useFolder, Gtk::PACK_SHRINK,4); - -#if defined(__APPLE__) || defined(__linux__) - // At the time of writing (2013-11-11) the gtkmm FileChooserButton with ACTION_SELECT_FOLDER - // is so buggy on these platforms (OS X and Linux) that we rather employ this ugly button hack. - // When/if GTKMM gets fixed we can go back to use the FileChooserButton, like we do on Windows. - outdirFolderButton = Gtk::manage (new Gtk::Button("(" + M("GENERAL_NONE") + ")")); - outdirFolderButton->set_alignment(0.0, 0.0); - hb3->pack_start (*outdirFolderButton); - outdirFolderButton->signal_pressed().connect( sigc::mem_fun(*this, &BatchQueuePanel::pathFolderButtonPressed) ); - outdirFolderButton->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT")); - outdirFolderButton->set_label(makeFolderLabel(options.savePathFolder)); - Gtk::Image* folderImg = Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU)); - folderImg->show (); - outdirFolderButton->set_image (*folderImg); - outdirFolder = 0; -#else - outdirFolder = Gtk::manage (new MyFileChooserButton (M("PREFERENCES_OUTDIRFOLDER"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); - hb3->pack_start (*outdirFolder); - outdirFolder->signal_current_folder_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::pathFolderChanged)); - outdirFolder->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT")); - if (safe_file_test (options.savePathFolder, Glib::FILE_TEST_IS_DIR)) - outdirFolder->set_current_folder (options.savePathFolder); - outdirFolderButton = 0; -#endif - - odvb->pack_start (*hb3, Gtk::PACK_SHRINK, 4); - useFolder->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT")); - Gtk::RadioButton::Group g = useTemplate->get_group(); - useFolder->set_group (g); - fdir->add (*odvb); - - // Output file format selection - fformat = Gtk::manage (new Gtk::Frame (M("PREFERENCES_FILEFORMAT"))); - saveFormatPanel = Gtk::manage (new SaveFormatPanel ()); - fformat->add (*saveFormatPanel); - - saveFormatPanel->init (options.saveFormatBatch); - outdirTemplate->set_text (options.savePathTemplate); - useTemplate->set_active (options.saveUsePathTemplate); - useFolder->set_active (!options.saveUsePathTemplate); - - // setup signal handlers - outdirTemplate->signal_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); - useTemplate->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); - useFolder->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); - saveFormatPanel->setListener (this); - - // setup button bar - topBox = Gtk::manage (new Gtk::HBox ()); - pack_start (*topBox, Gtk::PACK_SHRINK); - - topBox->pack_start (*batchQueueButtonBox, Gtk::PACK_SHRINK, 4); - topBox->pack_start (*fdir); - topBox->pack_start (*fformat, Gtk::PACK_SHRINK, 4); - - // add middle browser area - pack_start (*batchQueue); - - // lower box with thumbnail zoom - bottomBox = Gtk::manage (new Gtk::HBox ()); - pack_start (*bottomBox, Gtk::PACK_SHRINK); - - // thumbnail zoom - Gtk::HBox* zoomBox = Gtk::manage (new Gtk::HBox ()); - zoomBox->pack_start (*Gtk::manage (new Gtk::VSeparator), Gtk::PACK_SHRINK, 4); - Gtk::Label* zoomLabel = Gtk::manage (new Gtk::Label (Glib::ustring("")+M("FILEBROWSER_THUMBSIZE")+":")); - zoomLabel->set_use_markup (true); - zoomBox->pack_start (*zoomLabel, Gtk::PACK_SHRINK, 4); - zoomInButton = Gtk::manage (new Gtk::Button ()); - zoomInButton->set_image (*Gtk::manage (new RTImage ("gtk-zoom-in.png"))); - zoomInButton->signal_pressed().connect (sigc::mem_fun(*batchQueue, &BatchQueue::zoomIn)); - zoomInButton->set_relief (Gtk::RELIEF_NONE); - zoomInButton->set_tooltip_markup (M("FILEBROWSER_ZOOMINHINT")); - zoomBox->pack_end (*zoomInButton, Gtk::PACK_SHRINK); - zoomOutButton = Gtk::manage (new Gtk::Button ()); - zoomOutButton->set_image (*Gtk::manage (new RTImage ("gtk-zoom-out.png"))); - zoomOutButton->signal_pressed().connect (sigc::mem_fun(*batchQueue, &BatchQueue::zoomOut)); - zoomOutButton->set_relief (Gtk::RELIEF_NONE); - zoomOutButton->set_tooltip_markup (M("FILEBROWSER_ZOOMOUTHINT")); - zoomBox->pack_end (*zoomOutButton, Gtk::PACK_SHRINK); - bottomBox->pack_end (*zoomBox, Gtk::PACK_SHRINK); - - - batchQueue->setBatchQueueListener (this); - - show_all (); - if (batchQueue->loadBatchQueue ()) { - g_idle_add_full (G_PRIORITY_LOW, processLoadedBatchQueueUIThread, batchQueue, NULL); - } -} - -// it is expected to have a non null forceOrientation value on Preferences update only. In this case, qsize is ingored and computed automatically -void BatchQueuePanel::updateTab (int qsize, int forceOrientation) -{ - Gtk::Notebook *nb =(Gtk::Notebook *)(this->get_parent()); - - if (forceOrientation > 0) - qsize = batchQueue->getEntries().size(); - - if ((forceOrientation==0 && options.mainNBVertical) || (forceOrientation==2)) { - Gtk::VBox* vbb = Gtk::manage (new Gtk::VBox ()); - Gtk::Label* l; - - if(!qsize ){ - vbb->pack_start (*Gtk::manage (new RTImage ("processing.png"))); - l=Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_BATCHQUEUE")) ); - } else if( start->get_active () ){ - vbb->pack_start (*Gtk::manage (new RTImage ("processing-play.png"))); - l=Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]")); - } else { - vbb->pack_start (*Gtk::manage (new RTImage ("processing-pause.png"))); - l=Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]" )); - } - l->set_angle (90); - vbb->pack_start (*l); - vbb->set_spacing (2); - vbb->set_tooltip_markup (M("MAIN_FRAME_BATCHQUEUE_TOOLTIP")); - vbb->show_all (); - nb->set_tab_label(*this,*vbb); - } else { - Gtk::HBox* hbb = Gtk::manage (new Gtk::HBox ()); - if (!qsize ) { - hbb->pack_start (*Gtk::manage (new RTImage ("processing.png"))); - hbb->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE") ))); - } else if ( start->get_active () ){ - hbb->pack_start (*Gtk::manage (new RTImage ("processing-play.png"))); - hbb->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]" ))); - } else { - hbb->pack_start (*Gtk::manage (new RTImage ("processing-pause.png"))); - hbb->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]" ))); - } - hbb->set_spacing (2); - hbb->set_tooltip_markup (M("MAIN_FRAME_BATCHQUEUE_TOOLTIP")); - hbb->show_all (); - nb->set_tab_label(*this,*hbb); - } -} - -void BatchQueuePanel::queueSizeChanged (int qsize, bool queueEmptied, bool queueError, Glib::ustring queueErrorMessage) -{ - updateTab ( qsize); - - if (queueEmptied || queueError) { - stopBatchProc (); - fdir->set_sensitive (true); - fformat->set_sensitive (true); - - SoundManager::playSoundAsync(options.sndBatchQueueDone); - } - if (queueError) { - Gtk::MessageDialog msgd (queueErrorMessage, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); - msgd.run (); - } -} - -void BatchQueuePanel::startBatchProc () { - - stopConnection.block (true); - startConnection.block (true); - stop->set_active (false); - start->set_active (true); - stopConnection.block (false); - startConnection.block (false); - - if (batchQueue->hasJobs()) { - fdir->set_sensitive (false); - fformat->set_sensitive (false); - saveOptions(); - batchQueue->startProcessing (); - } - else - stopBatchProc (); - - updateTab (batchQueue->getEntries().size()); -} - -void BatchQueuePanel::stopBatchProc () { - - stopConnection.block (true); - startConnection.block (true); - stop->set_active (true); - start->set_active (false); - stopConnection.block (false); - startConnection.block (false); - updateTab (batchQueue->getEntries().size()); -} - -void BatchQueuePanel::addBatchQueueJobs ( std::vector &entries, bool head) { - - batchQueue->addEntries (entries, head); - - if (stop->get_active () && autoStart->get_active ()) - startBatchProc (); -} - -bool BatchQueuePanel::canStartNext () { - - if (start->get_active ()) - return true; - else { - fdir->set_sensitive (true); - fformat->set_sensitive (true); - return false; - } -} - -void BatchQueuePanel::saveOptions () { - - options.savePathTemplate = outdirTemplate->get_text(); - options.saveUsePathTemplate = useTemplate->get_active(); - options.procQueueEnabled = autoStart->get_active (); -} - -void BatchQueuePanel::pathFolderButtonPressed () { - - Gtk::FileChooserDialog fc(M("PREFERENCES_OUTDIRFOLDER"),Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER ); - fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); - fc.add_button( Gtk::StockID("gtk-ok"), Gtk::RESPONSE_OK); - fc.set_filename(options.savePathFolder); - fc.set_transient_for(*parent); - int result = fc.run(); - if (result == Gtk::RESPONSE_OK) { - if (safe_file_test(fc.get_current_folder(), Glib::FILE_TEST_IS_DIR)) { - options.savePathFolder = fc.get_current_folder(); - outdirFolderButton->set_label(makeFolderLabel(options.savePathFolder)); - } - } -} - -// We only want to save the following when it changes, -// since these settings are shared with editorpanel : -void BatchQueuePanel::pathFolderChanged () { - - options.savePathFolder = outdirFolder->get_current_folder(); -} - -void BatchQueuePanel::formatChanged (Glib::ustring f) { - - options.saveFormatBatch = saveFormatPanel->getFormat (); - -} - -bool BatchQueuePanel::handleShortcutKey (GdkEventKey* event) { - bool ctrl = event->state & GDK_CONTROL_MASK; - if (ctrl){ - switch(event->keyval) { - case GDK_s: - if (start->get_active()) { - stopBatchProc(); - } else { - startBatchProc(); - } - return true; - } - } - return batchQueue->keyPressed (event); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "batchqueuepanel.h" +#include "options.h" +#include "preferences.h" +#include "multilangmgr.h" +#include "rtwindow.h" +#include "soundman.h" +#include "../rtengine/safegtk.h" +#include "rtimage.h" + +struct BQProcessLoaded { + BatchQueue* bq; +}; + +int processLoadedBatchQueueUIThread (void* data) { + + BatchQueue* bq = static_cast(data); + bq->resizeLoadedQueue(); + return 0; +} + +static Glib::ustring makeFolderLabel(Glib::ustring path) +{ + if (!safe_file_test (path, Glib::FILE_TEST_IS_DIR)) + return "(" + M("GENERAL_NONE") + ")"; + if (path.size() > 40) { + size_t last_ds = path.find_last_of (G_DIR_SEPARATOR); + if (last_ds != Glib::ustring::npos && last_ds > 10) { + path = "..." + path.substr(last_ds); + } + } + return path; +} + +BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) { + + batchQueue = Gtk::manage( new BatchQueue(aFileCatalog) ); + + // construct batch queue panel with the extra "start" and "stop" button + Gtk::VBox* batchQueueButtonBox = Gtk::manage (new Gtk::VBox); + start = Gtk::manage (new Gtk::ToggleButton (M("FILEBROWSER_STARTPROCESSING"))); + stop = Gtk::manage (new Gtk::ToggleButton (M("FILEBROWSER_STOPPROCESSING"))); + autoStart = Gtk::manage (new Gtk::CheckButton (M("BATCHQUEUE_AUTOSTART"))); + start->set_tooltip_markup (M("FILEBROWSER_STARTPROCESSINGHINT")); + stop->set_tooltip_markup (M("FILEBROWSER_STOPPROCESSINGHINT")); + autoStart->set_tooltip_text (M("FILEBROWSER_TOOLTIP_STOPPROCESSING")); + start->set_active (false); + stop->set_active (true); + autoStart->set_active (options.procQueueEnabled); + + start->set_image (*Gtk::manage (new RTImage ("gtk-media-play.png"))); + startConnection = start->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::startBatchProc)); + stop->set_image (*Gtk::manage (new RTImage ("gtk-media-stop.png"))); + stopConnection = stop->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::stopBatchProc)); + batchQueueButtonBox->pack_start (*start, Gtk::PACK_SHRINK, 4); + batchQueueButtonBox->pack_start (*stop, Gtk::PACK_SHRINK, 4); + batchQueueButtonBox->pack_start (*autoStart, Gtk::PACK_SHRINK, 4); + + // Output directory selection + fdir = Gtk::manage (new Gtk::Frame (M("PREFERENCES_OUTDIR"))); + Gtk::VBox* odvb = Gtk::manage (new Gtk::VBox ()); + odvb->set_border_width (4); + Gtk::HBox* hb2 = Gtk::manage (new Gtk::HBox ()); + useTemplate = Gtk::manage (new Gtk::RadioButton (M("PREFERENCES_OUTDIRTEMPLATE")+":")); + hb2->pack_start (*useTemplate, Gtk::PACK_SHRINK,4); + outdirTemplate = Gtk::manage (new Gtk::Entry ()); + hb2->pack_start (*outdirTemplate); + odvb->pack_start (*hb2, Gtk::PACK_SHRINK, 4); + outdirTemplate->set_tooltip_markup (M("PREFERENCES_OUTDIRTEMPLATEHINT")); + useTemplate->set_tooltip_markup (M("PREFERENCES_OUTDIRTEMPLATEHINT")); + Gtk::HBox* hb3 = Gtk::manage (new Gtk::HBox ()); + useFolder = Gtk::manage (new Gtk::RadioButton (M("PREFERENCES_OUTDIRFOLDER")+":")); + hb3->pack_start (*useFolder, Gtk::PACK_SHRINK,4); + +#if defined(__APPLE__) || defined(__linux__) + // At the time of writing (2013-11-11) the gtkmm FileChooserButton with ACTION_SELECT_FOLDER + // is so buggy on these platforms (OS X and Linux) that we rather employ this ugly button hack. + // When/if GTKMM gets fixed we can go back to use the FileChooserButton, like we do on Windows. + outdirFolderButton = Gtk::manage (new Gtk::Button("(" + M("GENERAL_NONE") + ")")); + outdirFolderButton->set_alignment(0.0, 0.0); + hb3->pack_start (*outdirFolderButton); + outdirFolderButton->signal_pressed().connect( sigc::mem_fun(*this, &BatchQueuePanel::pathFolderButtonPressed) ); + outdirFolderButton->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT")); + outdirFolderButton->set_label(makeFolderLabel(options.savePathFolder)); + Gtk::Image* folderImg = Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU)); + folderImg->show (); + outdirFolderButton->set_image (*folderImg); + outdirFolder = 0; +#else + outdirFolder = Gtk::manage (new MyFileChooserButton (M("PREFERENCES_OUTDIRFOLDER"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + hb3->pack_start (*outdirFolder); + outdirFolder->signal_current_folder_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::pathFolderChanged)); + outdirFolder->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT")); + if (safe_file_test (options.savePathFolder, Glib::FILE_TEST_IS_DIR)) + outdirFolder->set_current_folder (options.savePathFolder); + outdirFolderButton = 0; +#endif + + odvb->pack_start (*hb3, Gtk::PACK_SHRINK, 4); + useFolder->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT")); + Gtk::RadioButton::Group g = useTemplate->get_group(); + useFolder->set_group (g); + fdir->add (*odvb); + + // Output file format selection + fformat = Gtk::manage (new Gtk::Frame (M("PREFERENCES_FILEFORMAT"))); + saveFormatPanel = Gtk::manage (new SaveFormatPanel ()); + fformat->add (*saveFormatPanel); + + saveFormatPanel->init (options.saveFormatBatch); + outdirTemplate->set_text (options.savePathTemplate); + useTemplate->set_active (options.saveUsePathTemplate); + useFolder->set_active (!options.saveUsePathTemplate); + + // setup signal handlers + outdirTemplate->signal_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); + useTemplate->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); + useFolder->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); + saveFormatPanel->setListener (this); + + // setup button bar + topBox = Gtk::manage (new Gtk::HBox ()); + pack_start (*topBox, Gtk::PACK_SHRINK); + + topBox->pack_start (*batchQueueButtonBox, Gtk::PACK_SHRINK, 4); + topBox->pack_start (*fdir); + topBox->pack_start (*fformat, Gtk::PACK_SHRINK, 4); + + // add middle browser area + pack_start (*batchQueue); + + // lower box with thumbnail zoom + bottomBox = Gtk::manage (new Gtk::HBox ()); + pack_start (*bottomBox, Gtk::PACK_SHRINK); + + // thumbnail zoom + Gtk::HBox* zoomBox = Gtk::manage (new Gtk::HBox ()); + zoomBox->pack_start (*Gtk::manage (new Gtk::VSeparator), Gtk::PACK_SHRINK, 4); + Gtk::Label* zoomLabel = Gtk::manage (new Gtk::Label (Glib::ustring("")+M("FILEBROWSER_THUMBSIZE")+":")); + zoomLabel->set_use_markup (true); + zoomBox->pack_start (*zoomLabel, Gtk::PACK_SHRINK, 4); + zoomInButton = Gtk::manage (new Gtk::Button ()); + zoomInButton->set_image (*Gtk::manage (new RTImage ("gtk-zoom-in.png"))); + zoomInButton->signal_pressed().connect (sigc::mem_fun(*batchQueue, &BatchQueue::zoomIn)); + zoomInButton->set_relief (Gtk::RELIEF_NONE); + zoomInButton->set_tooltip_markup (M("FILEBROWSER_ZOOMINHINT")); + zoomBox->pack_end (*zoomInButton, Gtk::PACK_SHRINK); + zoomOutButton = Gtk::manage (new Gtk::Button ()); + zoomOutButton->set_image (*Gtk::manage (new RTImage ("gtk-zoom-out.png"))); + zoomOutButton->signal_pressed().connect (sigc::mem_fun(*batchQueue, &BatchQueue::zoomOut)); + zoomOutButton->set_relief (Gtk::RELIEF_NONE); + zoomOutButton->set_tooltip_markup (M("FILEBROWSER_ZOOMOUTHINT")); + zoomBox->pack_end (*zoomOutButton, Gtk::PACK_SHRINK); + bottomBox->pack_end (*zoomBox, Gtk::PACK_SHRINK); + + + batchQueue->setBatchQueueListener (this); + + show_all (); + if (batchQueue->loadBatchQueue ()) { + g_idle_add_full (G_PRIORITY_LOW, processLoadedBatchQueueUIThread, batchQueue, NULL); + } +} + +// it is expected to have a non null forceOrientation value on Preferences update only. In this case, qsize is ingored and computed automatically +void BatchQueuePanel::updateTab (int qsize, int forceOrientation) +{ + Gtk::Notebook *nb =(Gtk::Notebook *)(this->get_parent()); + + if (forceOrientation > 0) + qsize = batchQueue->getEntries().size(); + + if ((forceOrientation==0 && options.mainNBVertical) || (forceOrientation==2)) { + Gtk::VBox* vbb = Gtk::manage (new Gtk::VBox ()); + Gtk::Label* l; + + if(!qsize ){ + vbb->pack_start (*Gtk::manage (new RTImage ("processing.png"))); + l=Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_BATCHQUEUE")) ); + } else if( start->get_active () ){ + vbb->pack_start (*Gtk::manage (new RTImage ("processing-play.png"))); + l=Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]")); + } else { + vbb->pack_start (*Gtk::manage (new RTImage ("processing-pause.png"))); + l=Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]" )); + } + l->set_angle (90); + vbb->pack_start (*l); + vbb->set_spacing (2); + vbb->set_tooltip_markup (M("MAIN_FRAME_BATCHQUEUE_TOOLTIP")); + vbb->show_all (); + nb->set_tab_label(*this,*vbb); + } else { + Gtk::HBox* hbb = Gtk::manage (new Gtk::HBox ()); + if (!qsize ) { + hbb->pack_start (*Gtk::manage (new RTImage ("processing.png"))); + hbb->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE") ))); + } else if ( start->get_active () ){ + hbb->pack_start (*Gtk::manage (new RTImage ("processing-play.png"))); + hbb->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]" ))); + } else { + hbb->pack_start (*Gtk::manage (new RTImage ("processing-pause.png"))); + hbb->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]" ))); + } + hbb->set_spacing (2); + hbb->set_tooltip_markup (M("MAIN_FRAME_BATCHQUEUE_TOOLTIP")); + hbb->show_all (); + nb->set_tab_label(*this,*hbb); + } +} + +void BatchQueuePanel::queueSizeChanged (int qsize, bool queueEmptied, bool queueError, Glib::ustring queueErrorMessage) +{ + updateTab ( qsize); + + if (queueEmptied || queueError) { + stopBatchProc (); + fdir->set_sensitive (true); + fformat->set_sensitive (true); + + SoundManager::playSoundAsync(options.sndBatchQueueDone); + } + if (queueError) { + Gtk::MessageDialog msgd (queueErrorMessage, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd.run (); + } +} + +void BatchQueuePanel::startBatchProc () { + + stopConnection.block (true); + startConnection.block (true); + stop->set_active (false); + start->set_active (true); + stopConnection.block (false); + startConnection.block (false); + + if (batchQueue->hasJobs()) { + fdir->set_sensitive (false); + fformat->set_sensitive (false); + saveOptions(); + batchQueue->startProcessing (); + } + else + stopBatchProc (); + + updateTab (batchQueue->getEntries().size()); +} + +void BatchQueuePanel::stopBatchProc () { + + stopConnection.block (true); + startConnection.block (true); + stop->set_active (true); + start->set_active (false); + stopConnection.block (false); + startConnection.block (false); + updateTab (batchQueue->getEntries().size()); +} + +void BatchQueuePanel::addBatchQueueJobs ( std::vector &entries, bool head) { + + batchQueue->addEntries (entries, head); + + if (stop->get_active () && autoStart->get_active ()) + startBatchProc (); +} + +bool BatchQueuePanel::canStartNext () { + + if (start->get_active ()) + return true; + else { + fdir->set_sensitive (true); + fformat->set_sensitive (true); + return false; + } +} + +void BatchQueuePanel::saveOptions () { + + options.savePathTemplate = outdirTemplate->get_text(); + options.saveUsePathTemplate = useTemplate->get_active(); + options.procQueueEnabled = autoStart->get_active (); +} + +void BatchQueuePanel::pathFolderButtonPressed () { + + Gtk::FileChooserDialog fc(M("PREFERENCES_OUTDIRFOLDER"),Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER ); + fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + fc.add_button( Gtk::StockID("gtk-ok"), Gtk::RESPONSE_OK); + fc.set_filename(options.savePathFolder); + fc.set_transient_for(*parent); + int result = fc.run(); + if (result == Gtk::RESPONSE_OK) { + if (safe_file_test(fc.get_current_folder(), Glib::FILE_TEST_IS_DIR)) { + options.savePathFolder = fc.get_current_folder(); + outdirFolderButton->set_label(makeFolderLabel(options.savePathFolder)); + } + } +} + +// We only want to save the following when it changes, +// since these settings are shared with editorpanel : +void BatchQueuePanel::pathFolderChanged () { + + options.savePathFolder = outdirFolder->get_current_folder(); +} + +void BatchQueuePanel::formatChanged (Glib::ustring f) { + + options.saveFormatBatch = saveFormatPanel->getFormat (); + +} + +bool BatchQueuePanel::handleShortcutKey (GdkEventKey* event) { + bool ctrl = event->state & GDK_CONTROL_MASK; + if (ctrl){ + switch(event->keyval) { + case GDK_s: + if (start->get_active()) { + stopBatchProc(); + } else { + startBatchProc(); + } + return true; + } + } + return batchQueue->keyPressed (event); +} diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index da07baff2..8e83a6493 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -1,634 +1,634 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "multilangmgr.h" -#include "batchtoolpanelcoord.h" -#include "options.h" -#include "filepanel.h" -#include "procparamchangers.h" -#include "addsetids.h" - -using namespace rtengine::procparams; - -BatchToolPanelCoordinator::BatchToolPanelCoordinator (FilePanel* parent) : ToolPanelCoordinator(), somethingChanged(false), parent(parent) { - - blockedUpdate = false; - // remove exif panel and iptc panel - std::vector::iterator epi = std::find (toolPanels.begin(), toolPanels.end(), exifpanel); - if (epi!=toolPanels.end()) - toolPanels.erase (epi); - std::vector::iterator ipi = std::find (toolPanels.begin(), toolPanels.end(), iptcpanel); - if (ipi!=toolPanels.end()) - toolPanels.erase (ipi); - toolPanelNotebook->remove_page (*metadataPanel); - metadataPanel = 0; - toiM = 0; - - for (size_t i=0; isetBatchMode (true); -} - -void BatchToolPanelCoordinator::selectionChanged (const std::vector& selected) { - - if (selected!=this->selected) { - closeSession (); - this->selected = selected; - selFileNames.clear (); - for (size_t i=0; igetFileName ()); - initSession (); - } -} - -void BatchToolPanelCoordinator::closeSession (bool save) { - - pparamsEdited.set (false); - - for (size_t i=0; iremoveThumbnailListener (this); - - if (somethingChanged && save) { - - // read new values from the gui - for (size_t i=0; iwrite (&pparams, &pparamsEdited); - - // combine with initial parameters and set - ProcParams newParams; - for (size_t i=0; itrimValues (&newParams); - - selected[i]->setProcParams (newParams, NULL, BATCHEDITOR, true); - } - } - for (size_t i=0; iclearParamChanges (); -} - -void BatchToolPanelCoordinator::initSession () { - - somethingChanged = false; - - initialPP.resize (selected.size()); - for (size_t i=0; igetProcParams (); - selected[i]->applyAutoExp (initialPP[i]); - selected[i]->addThumbnailListener (this); - } - - // compare all the ProcParams and describe which parameters has different (i.e. inconsistent) values in pparamsEdited - pparamsEdited.initFrom (initialPP); - - crop->setDimensions (100000, 100000); - -/* if (!selected.empty()) { - pparams = selected[0]->getProcParams (); - for (int i=0; isetDefaults (&pparams, &pparamsEdited); - toolPanels[i]->read (&pparams, &pparamsEdited); - } - for (int i=0; iprocParamsChanged (&pparams, rtengine::EvPhotoLoaded, "batch processing", &pparamsEdited); - } -*/ - - if (!selected.empty()) { - - // The first selected image (in the thumbnail list, not the click list) is used to populate the EditorPanel and set the default values - pparams = selected[0]->getProcParams (); - - coarse->initBatchBehavior (); - - if (selected.size()==1) { - - for (size_t i=0; isetMultiImage(false); - - toneCurve->setAdjusterBehavior (false, false, false, false, false, false, false, false); - lcurve->setAdjusterBehavior (false, false, false); - whitebalance->setAdjusterBehavior (false, false, false); - vibrance->setAdjusterBehavior (false, false); - vignetting->setAdjusterBehavior (false, false, false, false); - colorappearance->setAdjusterBehavior (false, false, false, false, false, false, false, false, false, false, false, false, false); - rotate->setAdjusterBehavior (false); - distortion->setAdjusterBehavior (false); - perspective->setAdjusterBehavior (false); - gradient->setAdjusterBehavior (false, false, false, false); - pcvignette->setAdjusterBehavior (false, false, false); - cacorrection->setAdjusterBehavior (false); - sharpening->setAdjusterBehavior (false); - sharpenEdge->setAdjusterBehavior (false, false); - sharpenMicro->setAdjusterBehavior (false, false); - icm->setAdjusterBehavior (false, false); - - chmixer->setAdjusterBehavior (false); - blackwhite->setAdjusterBehavior (false,false); - colortoning->setAdjusterBehavior (false, false, false, false, false); - filmSimulation->setAdjusterBehavior(false); - - shadowshighlights->setAdjusterBehavior (false, false, false); - dirpyrequalizer->setAdjusterBehavior (false, false, false); - wavelet->setAdjusterBehavior (false, false, false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false, false, false); - dirpyrdenoise->setAdjusterBehavior (false, false,false,false,false,false, false); - bayerpreprocess->setAdjusterBehavior (false, false); - rawcacorrection->setAdjusterBehavior (false); - flatfield->setAdjusterBehavior(false); - rawexposure->setAdjusterBehavior (false, false); - bayerrawexposure->setAdjusterBehavior (false); - xtransrawexposure->setAdjusterBehavior (false); - } - else { - - for (size_t i=0; isetMultiImage(true); - - toneCurve->setAdjusterBehavior (options.baBehav[ADDSET_TC_EXPCOMP], options.baBehav[ADDSET_TC_HLCOMPAMOUNT],options.baBehav[ADDSET_TC_HLCOMPTHRESH], options.baBehav[ADDSET_TC_BRIGHTNESS], options.baBehav[ADDSET_TC_BLACKLEVEL],options.baBehav[ADDSET_TC_SHCOMP], options.baBehav[ADDSET_TC_CONTRAST], options.baBehav[ADDSET_TC_SATURATION]); - lcurve->setAdjusterBehavior (options.baBehav[ADDSET_LC_BRIGHTNESS], options.baBehav[ADDSET_LC_CONTRAST], options.baBehav[ADDSET_LC_CHROMATICITY]); - whitebalance->setAdjusterBehavior (options.baBehav[ADDSET_WB_TEMPERATURE], options.baBehav[ADDSET_WB_GREEN], options.baBehav[ADDSET_WB_EQUAL]); - vibrance->setAdjusterBehavior (options.baBehav[ADDSET_VIBRANCE_PASTELS], options.baBehav[ADDSET_VIBRANCE_SATURATED]); - vignetting->setAdjusterBehavior (options.baBehav[ADDSET_VIGN_AMOUNT], options.baBehav[ADDSET_VIGN_RADIUS], options.baBehav[ADDSET_VIGN_STRENGTH], options.baBehav[ADDSET_VIGN_CENTER]); - colorappearance->setAdjusterBehavior (options.baBehav[ADDSET_CAT_DEGREE], options.baBehav[ADDSET_CAT_ADAPTSCENE], options.baBehav[ADDSET_CAT_ADAPTVIEWING],options.baBehav[ADDSET_CAT_BADPIX], options.baBehav[ADDSET_CAT_LIGHT], options.baBehav[ADDSET_CAT_CHROMA],options.baBehav[ADDSET_CAT_CONTRAST],options.baBehav[ADDSET_CAT_RSTPRO],options.baBehav[ADDSET_CAT_BRIGHT],options.baBehav[ADDSET_CAT_CONTRAST_Q],options.baBehav[ADDSET_CAT_CHROMA_S],options.baBehav[ADDSET_CAT_CHROMA_M],options.baBehav[ADDSET_CAT_HUE]); - rotate->setAdjusterBehavior (options.baBehav[ADDSET_ROTATE_DEGREE]); - distortion->setAdjusterBehavior (options.baBehav[ADDSET_DIST_AMOUNT]); - perspective->setAdjusterBehavior (options.baBehav[ADDSET_PERSPECTIVE]); - gradient->setAdjusterBehavior (options.baBehav[ADDSET_GRADIENT_DEGREE], options.baBehav[ADDSET_GRADIENT_FEATHER], options.baBehav[ADDSET_GRADIENT_STRENGTH], options.baBehav[ADDSET_GRADIENT_CENTER]); - pcvignette->setAdjusterBehavior (options.baBehav[ADDSET_PCVIGNETTE_STRENGTH], options.baBehav[ADDSET_PCVIGNETTE_FEATHER], options.baBehav[ADDSET_PCVIGNETTE_ROUNDNESS]); - cacorrection->setAdjusterBehavior (options.baBehav[ADDSET_CA]); - sharpening->setAdjusterBehavior (options.baBehav[ADDSET_SHARP_AMOUNT]); - sharpenEdge->setAdjusterBehavior (options.baBehav[ADDSET_SHARPENEDGE_AMOUNT],options.baBehav[ADDSET_SHARPENEDGE_PASS]); - sharpenMicro->setAdjusterBehavior (options.baBehav[ADDSET_SHARPENMICRO_AMOUNT],options.baBehav[ADDSET_SHARPENMICRO_UNIFORMITY]); - icm->setAdjusterBehavior (options.baBehav[ADDSET_FREE_OUPUT_GAMMA],options.baBehav[ADDSET_FREE_OUTPUT_SLOPE]); -// colortoning->setAdjusterBehavior (options.baBehav[ADDSET_COLORTONING_SPLIT], options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD], options.baBehav[ADDSET_COLORTONING_SATOPACITY], options.baBehav[ADDSET_COLORTONING_STRPROTECT], options.baBehav[ADDSET_COLORTONING_BALANCE]); - colortoning->setAdjusterBehavior (options.baBehav[ADDSET_COLORTONING_SPLIT], options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD], options.baBehav[ADDSET_COLORTONING_SATOPACITY], options.baBehav[ADDSET_COLORTONING_STRENGTH], options.baBehav[ADDSET_COLORTONING_BALANCE]); - filmSimulation->setAdjusterBehavior(options.baBehav[ADDSET_FILMSIMULATION_STRENGTH]); - - chmixer->setAdjusterBehavior (options.baBehav[ADDSET_CHMIXER] ); - blackwhite->setAdjusterBehavior (options.baBehav[ADDSET_BLACKWHITE_HUES],options.baBehav[ADDSET_BLACKWHITE_GAMMA]); - shadowshighlights->setAdjusterBehavior (options.baBehav[ADDSET_SH_HIGHLIGHTS], options.baBehav[ADDSET_SH_SHADOWS], options.baBehav[ADDSET_SH_LOCALCONTRAST]); - dirpyrequalizer->setAdjusterBehavior (options.baBehav[ADDSET_DIRPYREQ], options.baBehav[ADDSET_DIRPYREQ_THRESHOLD], options.baBehav[ADDSET_DIRPYREQ_SKINPROTECT]); - wavelet->setAdjusterBehavior (options.baBehav[ADDSET_WA], options.baBehav[ADDSET_WA_THRESHOLD], options.baBehav[ADDSET_WA_THRESHOLD2],options.baBehav[ADDSET_WA_THRES],options.baBehav[ADDSET_WA_CHRO],options.baBehav[ADDSET_WA_CHROMA],options.baBehav[ADDSET_WA_CONTRAST],options.baBehav[ADDSET_WA_SKINPROTECT],options.baBehav[ADDSET_WA_RESCHRO],options.baBehav[ADDSET_WA_TMRS],options.baBehav[ADDSET_WA_RESCON],options.baBehav[ADDSET_WA_RESCONH],options.baBehav[ADDSET_WA_THRR],options.baBehav[ADDSET_WA_THRRH],options.baBehav[ADDSET_WA_SKYPROTECT], options.baBehav[ADDSET_WA_EDGRAD],options.baBehav[ADDSET_WA_EDGVAL],options.baBehav[ADDSET_WA_STRENGTH],options.baBehav[ADDSET_WA_GAMMA],options.baBehav[ADDSET_WA_EDGEDETECT], options.baBehav[ADDSET_WA_EDGEDETECTTHR], options.baBehav[ADDSET_WA_EDGEDETECTTHR2]); - dirpyrdenoise->setAdjusterBehavior (options.baBehav[ADDSET_DIRPYRDN_LUMA],options.baBehav[ADDSET_DIRPYRDN_LUMDET],options.baBehav[ADDSET_DIRPYRDN_CHROMA],options.baBehav[ADDSET_DIRPYRDN_CHROMARED],options.baBehav[ADDSET_DIRPYRDN_CHROMABLUE], options.baBehav[ADDSET_DIRPYRDN_GAMMA], options.baBehav[ADDSET_DIRPYRDN_PASSES]); - bayerpreprocess->setAdjusterBehavior (options.baBehav[ADDSET_PREPROCESS_LINEDENOISE], options.baBehav[ADDSET_PREPROCESS_GREENEQUIL]); - rawcacorrection->setAdjusterBehavior (options.baBehav[ADDSET_RAWCACORR]); - flatfield->setAdjusterBehavior(options.baBehav[ADDSET_RAWFFCLIPCONTROL]); - rawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_LINEAR], options.baBehav[ADDSET_RAWEXPOS_PRESER]); - bayerrawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_BLACKS]); - xtransrawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_BLACKS]); - - if (options.baBehav[ADDSET_TC_EXPCOMP]) pparams.toneCurve.expcomp = 0; - if (options.baBehav[ADDSET_TC_HLCOMPAMOUNT]) pparams.toneCurve.hlcompr = 0; - if (options.baBehav[ADDSET_TC_HLCOMPTHRESH]) pparams.toneCurve.hlcomprthresh = 0; - if (options.baBehav[ADDSET_TC_BRIGHTNESS]) pparams.toneCurve.brightness = 0; - if (options.baBehav[ADDSET_TC_BLACKLEVEL]) pparams.toneCurve.black = 0; - if (options.baBehav[ADDSET_TC_SHCOMP]) pparams.toneCurve.shcompr = 0; - if (options.baBehav[ADDSET_TC_CONTRAST]) pparams.toneCurve.contrast = 0; - - if (options.baBehav[ADDSET_SH_HIGHLIGHTS]) pparams.sh.highlights = 0; - if (options.baBehav[ADDSET_SH_SHADOWS]) pparams.sh.shadows = 0; - if (options.baBehav[ADDSET_SH_LOCALCONTRAST]) pparams.sh.localcontrast = 0; - - if (options.baBehav[ADDSET_LC_BRIGHTNESS]) pparams.labCurve.brightness = 0; - if (options.baBehav[ADDSET_LC_CONTRAST]) pparams.labCurve.contrast = 0; - if (options.baBehav[ADDSET_LC_CHROMATICITY]) pparams.labCurve.chromaticity = 0; - - if (options.baBehav[ADDSET_SHARP_AMOUNT]) pparams.sharpening.amount = 0; - if (options.baBehav[ADDSET_SHARPENEDGE_AMOUNT]) pparams.sharpenEdge.amount = 0; - if (options.baBehav[ADDSET_SHARPENMICRO_AMOUNT]) pparams.sharpenMicro.amount = 0; - if (options.baBehav[ADDSET_SHARPENEDGE_PASS]) pparams.sharpenEdge.passes = 0; - if (options.baBehav[ADDSET_SHARPENMICRO_UNIFORMITY]) pparams.sharpenMicro.uniformity = 0; - - if (options.baBehav[ADDSET_CHMIXER]) for (int i=0; i<3; i++) pparams.chmixer.red[i] = pparams.chmixer.green[i] = pparams.chmixer.blue[i] = 0; - if (options.baBehav[ADDSET_BLACKWHITE_HUES]) pparams.blackwhite.mixerRed=pparams.blackwhite.mixerOrange=pparams.blackwhite.mixerYellow= - pparams.blackwhite.mixerGreen=pparams.blackwhite.mixerCyan=pparams.blackwhite.mixerBlue= - pparams.blackwhite.mixerMagenta=pparams.blackwhite.mixerPurple=0; - if (options.baBehav[ADDSET_BLACKWHITE_GAMMA]) pparams.blackwhite.gammaRed=pparams.blackwhite.gammaGreen=pparams.blackwhite.gammaBlue = 0; - - //if (options.baBehav[ADDSET_LD_EDGETOLERANCE]) pparams.lumaDenoise.edgetolerance = 0; - - if (options.baBehav[ADDSET_WB_TEMPERATURE]) pparams.wb.temperature = 0; - if (options.baBehav[ADDSET_WB_GREEN]) pparams.wb.green = 0; - if (options.baBehav[ADDSET_WB_EQUAL]) pparams.wb.equal = 0; - - if (options.baBehav[ADDSET_VIBRANCE_PASTELS]) pparams.vibrance.pastels = 0; - if (options.baBehav[ADDSET_VIBRANCE_SATURATED]) pparams.vibrance.saturated = 0; - - if (options.baBehav[ADDSET_CAT_DEGREE]) pparams.colorappearance.degree = 0; - if (options.baBehav[ADDSET_CAT_ADAPTSCENE]) pparams.colorappearance.adapscen = 0; - if (options.baBehav[ADDSET_CAT_ADAPTVIEWING]) pparams.colorappearance.adaplum = 0; - if (options.baBehav[ADDSET_CAT_BADPIX]) pparams.colorappearance.badpixsl = 0; - if (options.baBehav[ADDSET_CAT_LIGHT]) pparams.colorappearance.jlight = 0; - if (options.baBehav[ADDSET_CAT_BRIGHT]) pparams.colorappearance.qbright = 0; - if (options.baBehav[ADDSET_CAT_CHROMA]) pparams.colorappearance.chroma = 0; - if (options.baBehav[ADDSET_CAT_CHROMA_S]) pparams.colorappearance.schroma = 0; - if (options.baBehav[ADDSET_CAT_CHROMA_M]) pparams.colorappearance.mchroma = 0; - if (options.baBehav[ADDSET_CAT_RSTPRO]) pparams.colorappearance.rstprotection = 0; - if (options.baBehav[ADDSET_CAT_CONTRAST]) pparams.colorappearance.contrast = 0; - if (options.baBehav[ADDSET_CAT_CONTRAST_Q]) pparams.colorappearance.qcontrast = 0; - if (options.baBehav[ADDSET_CAT_HUE]) pparams.colorappearance.colorh = 0; - - if (options.baBehav[ADDSET_FREE_OUPUT_GAMMA]) pparams.icm.gampos = 0; - if (options.baBehav[ADDSET_FREE_OUTPUT_SLOPE]) pparams.icm.slpos = 0; - - //if (options.baBehav[ADDSET_CBOOST_AMOUNT]) pparams.colorBoost.amount = 0; - - //if (options.baBehav[ADDSET_CS_BLUEYELLOW]) pparams.colorShift.a = 0; - //if (options.baBehav[ADDSET_CS_GREENMAGENTA]) pparams.colorShift.b = 0; - if (options.baBehav[ADDSET_COLORTONING_SPLIT]) pparams.colorToning.redlow = pparams.colorToning.greenlow = pparams.colorToning.bluelow = - pparams.colorToning.redmed = pparams.colorToning.greenmed = pparams.colorToning.bluemed = - pparams.colorToning.redhigh = pparams.colorToning.greenhigh = pparams.colorToning.bluehigh = - pparams.colorToning.satlow = pparams.colorToning.sathigh = 0; - if (options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD]) pparams.colorToning.satProtectionThreshold = 0; - if (options.baBehav[ADDSET_COLORTONING_SATOPACITY]) pparams.colorToning.saturatedOpacity = 0; - if (options.baBehav[ADDSET_COLORTONING_BALANCE]) pparams.colorToning.balance = 0; - if (options.baBehav[ADDSET_COLORTONING_STRENGTH]) pparams.colorToning.strength = 0; - - if (options.baBehav[ADDSET_FILMSIMULATION_STRENGTH]) pparams.filmSimulation.strength = 0; - - if (options.baBehav[ADDSET_ROTATE_DEGREE]) pparams.rotate.degree = 0; - if (options.baBehav[ADDSET_DIST_AMOUNT]) pparams.distortion.amount = 0; - if (options.baBehav[ADDSET_PERSPECTIVE]) pparams.perspective.horizontal = pparams.perspective.vertical = 0; - if (options.baBehav[ADDSET_GRADIENT_DEGREE]) pparams.gradient.degree = 0; - if (options.baBehav[ADDSET_GRADIENT_FEATHER]) pparams.gradient.feather = 0; - if (options.baBehav[ADDSET_GRADIENT_STRENGTH]) pparams.gradient.strength = 0; - if (options.baBehav[ADDSET_GRADIENT_CENTER]) pparams.gradient.centerX = 0; - if (options.baBehav[ADDSET_GRADIENT_CENTER]) pparams.gradient.centerY = 0; - if (options.baBehav[ADDSET_PCVIGNETTE_STRENGTH]) pparams.pcvignette.strength = 0; - if (options.baBehav[ADDSET_PCVIGNETTE_FEATHER]) pparams.pcvignette.feather = 0; - if (options.baBehav[ADDSET_PCVIGNETTE_ROUNDNESS]) pparams.pcvignette.roundness = 0; - if (options.baBehav[ADDSET_CA]) pparams.cacorrection.red = 0; - if (options.baBehav[ADDSET_CA]) pparams.cacorrection.blue = 0; - if (options.baBehav[ADDSET_VIGN_AMOUNT]) pparams.vignetting.amount = 0; - if (options.baBehav[ADDSET_VIGN_RADIUS]) pparams.vignetting.radius = 0; - if (options.baBehav[ADDSET_VIGN_STRENGTH]) pparams.vignetting.strength = 0; - if (options.baBehav[ADDSET_VIGN_CENTER]) pparams.vignetting.centerX = 0; - if (options.baBehav[ADDSET_VIGN_CENTER]) pparams.vignetting.centerY = 0; - - if (options.baBehav[ADDSET_DIRPYREQ]) for (int i=0; i<6; i++) pparams.dirpyrequalizer.mult[i] = 0; - if (options.baBehav[ADDSET_DIRPYREQ_THRESHOLD]) pparams.dirpyrequalizer.threshold = 0; - if (options.baBehav[ADDSET_DIRPYREQ_SKINPROTECT]) pparams.dirpyrequalizer.skinprotect = 0; - - if (options.baBehav[ADDSET_WA]) for (int i=0; i<8; i++) pparams.wavelet.c[i] = 0; - if (options.baBehav[ADDSET_WA_THRESHOLD]) pparams.wavelet.threshold = 0; - if (options.baBehav[ADDSET_WA_THRESHOLD2]) pparams.wavelet.threshold2 = 0; - if (options.baBehav[ADDSET_WA_SKINPROTECT]) pparams.wavelet.skinprotect = 0; - if (options.baBehav[ADDSET_WA_CHRO]) pparams.wavelet.chro = 0; - if (options.baBehav[ADDSET_WA_CHROMA]) pparams.wavelet.chroma = 0; - if (options.baBehav[ADDSET_WA_CONTRAST]) pparams.wavelet.contrast = 0; - if (options.baBehav[ADDSET_WA_THRES]) pparams.wavelet.thres = 0; - if (options.baBehav[ADDSET_WA_RESCON]) pparams.wavelet.rescon = 0; - if (options.baBehav[ADDSET_WA_RESCONH]) pparams.wavelet.resconH = 0; - if (options.baBehav[ADDSET_WA_RESCHRO]) pparams.wavelet.reschro = 0; - if (options.baBehav[ADDSET_WA_TMRS]) pparams.wavelet.tmrs = 0; - if (options.baBehav[ADDSET_WA_THRR]) pparams.wavelet.thr = 0; - if (options.baBehav[ADDSET_WA_THRRH]) pparams.wavelet.thrH = 0; - if (options.baBehav[ADDSET_WA_SKYPROTECT]) pparams.wavelet.sky = 0; - if (options.baBehav[ADDSET_WA_EDGRAD]) pparams.wavelet.edgrad = 0; - if (options.baBehav[ADDSET_WA_EDGVAL]) pparams.wavelet.edgval = 0; - if (options.baBehav[ADDSET_WA_STRENGTH]) pparams.wavelet.strength = 0; - if (options.baBehav[ADDSET_WA_EDGEDETECT]) pparams.wavelet.edgedetect = 0; - if (options.baBehav[ADDSET_WA_GAMMA]) pparams.wavelet.gamma = 0; - - - if (options.baBehav[ADDSET_DIRPYRDN_LUMA]) pparams.dirpyrDenoise.luma = 0; - - if (options.baBehav[ADDSET_DIRPYRDN_CHROMA]) pparams.dirpyrDenoise.chroma = 0; - if (options.baBehav[ADDSET_DIRPYRDN_CHROMARED]) pparams.dirpyrDenoise.redchro = 0; - if (options.baBehav[ADDSET_DIRPYRDN_CHROMABLUE]) pparams.dirpyrDenoise.bluechro = 0; -// pparams.dirpyrDenoise.Ldetail = pparams.dirpyrDenoise.luma = pparams.dirpyrDenoise.chroma = 0; - if (options.baBehav[ADDSET_DIRPYRDN_GAMMA]) pparams.dirpyrDenoise.gamma = 0; - - if (options.baBehav[ADDSET_RAWCACORR]) pparams.raw.cablue = pparams.raw.cared = 0; - if (options.baBehav[ADDSET_RAWEXPOS_LINEAR]) pparams.raw.expos = 0; - if (options.baBehav[ADDSET_RAWEXPOS_PRESER]) pparams.raw.preser = 0; - if (options.baBehav[ADDSET_RAWEXPOS_BLACKS]) { - pparams.raw.bayersensor.black0 = pparams.raw.bayersensor.black1 = pparams.raw.bayersensor.black2 = pparams.raw.bayersensor.black3 = 0; - pparams.raw.xtranssensor.blackred = pparams.raw.xtranssensor.blackgreen = pparams.raw.xtranssensor.blackblue = 0; - } - if (options.baBehav[ADDSET_RAWFFCLIPCONTROL]) pparams.raw.ff_clipControl = 0; - - if (options.baBehav[ADDSET_PREPROCESS_GREENEQUIL]) pparams.raw.bayersensor.greenthresh = 0; - if (options.baBehav[ADDSET_PREPROCESS_LINEDENOISE]) pparams.raw.bayersensor.linenoise = 0; - } - - for (size_t i=0; isetDefaults (&pparams, &pparamsEdited); - toolPanels[i]->read (&pparams, &pparamsEdited); - // TODO: autoOpenCurve has been disabled because initSession is called on each parameter change from the editor panel, - // if the thumbnail remains selected in the DirectoryBrowser (i.e. always, unless the user think about deselecting it) - //toolPanels[i]->autoOpenCurve(); - } - for (size_t i=0; iprocParamsChanged (&pparams, rtengine::EvPhotoLoaded, M("BATCH_PROCESSING"), &pparamsEdited); - } -} - -void BatchToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr) { - - if (selected.empty()) - return; - - somethingChanged = true; - - pparamsEdited.set (false); - // read new values from the gui - for (size_t i=0; iwrite (&pparams, &pparamsEdited); - - // If only a single item is selected, we emulate the behaviour of the editor tool panel coordinator, - // otherwise we adjust the inital parameters on a per-image basis. - if (selected.size()==1) { - // Compensate rotation on flip - if (event==rtengine::EvCTHFlip || event==rtengine::EvCTVFlip) { - if (fabs(pparams.rotate.degree)>0.001) { - pparams.rotate.degree *= -1; - rotate->read (&pparams); - } - } - - int w, h; - selected[0]->getFinalSize (selected[0]->getProcParams (), w, h); - crop->setDimensions(w, h); - - // Some transformations change the crop and resize parameter for convenience. - if (event==rtengine::EvCTHFlip) { - crop->hFlipCrop (); - crop->write (&pparams, &pparamsEdited); - } - else if (event==rtengine::EvCTVFlip) { - crop->vFlipCrop (); - crop->write (&pparams, &pparamsEdited); - } - else if (event==rtengine::EvCTRotate) { - crop->rotateCrop (pparams.coarse.rotate, pparams.coarse.hflip, pparams.coarse.vflip); - crop->write (&pparams, &pparamsEdited); - resize->update (pparams.crop.enabled, pparams.crop.w, pparams.crop.h, w, h); - resize->write (&pparams, &pparamsEdited); - } - else if (event==rtengine::EvCrop) { - resize->update (pparams.crop.enabled, pparams.crop.w, pparams.crop.h); - resize->write (&pparams, &pparamsEdited); - } - } - else { - // Compensate rotation on flip - if (event==rtengine::EvCTHFlip || event==rtengine::EvCTVFlip) { - for (size_t i=0; i 0.001) { - initialPP[i].rotate.degree *= -1.0; - - pparamsEdited.rotate.degree = false; - } - } - } - - // some transformations make the crop change for convenience - if (event==rtengine::EvCTHFlip) { - for (size_t i=0; igetFinalSize (selected[i]->getProcParams (), w, h); - - rtengine::procparams::CropParams& crop = initialPP[i].crop; - crop.x = w - crop.x - crop.w; - - pparamsEdited.crop.x = false; - } - } - else if (event==rtengine::EvCTVFlip) { - for (size_t i=0; igetFinalSize (selected[i]->getProcParams (), w, h); - - rtengine::procparams::CropParams& crop = initialPP[i].crop; - crop.y = h - crop.y - crop.h; - - pparamsEdited.crop.y = false; - } - } - else if (event==rtengine::EvCTRotate) { - int newDeg = pparams.coarse.rotate; - for (size_t i=0; igetFinalSize (selected[i]->getProcParams (), w, h); - - int oldDeg = initialPP[i].coarse.rotate; - - rtengine::procparams::CropParams& crop = initialPP[i].crop; - int rotation = (360 + newDeg - oldDeg) % 360; - ProcParams pptemp = selected[i]->getProcParams(); // Get actual procparams - if((pptemp.coarse.hflip != pptemp.coarse.vflip) && ((rotation%180)==90)) - rotation = (rotation + 180)%360; - - - switch (rotation) { - case 90: - std::swap(crop.x, crop.y); - std::swap(crop.w, crop.h); - - crop.x = h - crop.x - crop.w; - break; - case 270: - std::swap(crop.x, crop.y); - std::swap(crop.w, crop.h); - - crop.y = w - crop.y - crop.h; - break; - case 180: - crop.x = w - crop.x - crop.w; - crop.y = h - crop.y - crop.h; - break; - } - - initialPP[i].coarse.rotate = newDeg; - - } - pparamsEdited.crop.x = false; - pparamsEdited.crop.y = false; - pparamsEdited.crop.w = false; - pparamsEdited.crop.h = false; - pparamsEdited.coarse.rotate = false; - } - } - - if (event==rtengine::EvAutoExp || event==rtengine::EvClip) - for (size_t i=0; iapplyAutoExp (initialPP[i]); - } - - if (event==rtengine::EvAutoDIST) { - for (size_t i=0; itrimValues (&newParams); - - selected[i]->setProcParams (newParams, NULL, BATCHEDITOR, false); - } - - for (size_t i=0; iprocParamsChanged (&pparams, event, descr, &pparamsEdited); -} - -void BatchToolPanelCoordinator::getAutoWB (double& temp, double& green, double equal) { - - if (!selected.empty()) - selected[0]->getAutoWB (temp, green, equal); -} - -void BatchToolPanelCoordinator::getCamWB (double& temp, double& green) { - - if (!selected.empty()) - selected[0]->getCamWB (temp, green); -} - -void BatchToolPanelCoordinator::optionsChanged () { - - closeSession (); - initSession (); -} - -void BatchToolPanelCoordinator::procParamsChanged (Thumbnail* thm, int whoChangedIt) { - - if (whoChangedIt!=BATCHEDITOR && !blockedUpdate) { - closeSession (false); - initSession (); - } -} - -void BatchToolPanelCoordinator::beginBatchPParamsChange(int numberOfEntries) { - - blockedUpdate = true; - if (numberOfEntries > 50) // Arbitrary amount - parent->set_sensitive(false); -} - -// The end of a batch pparams change triggers a close/initsession -void BatchToolPanelCoordinator::endBatchPParamsChange() { - //printf("BatchToolPanelCoordinator::endBatchPParamsChange / Nouvelle session!\n"); - closeSession (false); - initSession (); - blockedUpdate = false; - parent->set_sensitive(true); -} - -/* - * WARNING: profileChange is actually called by the History only. - * Using a Profile panel in the batch tool panel editor is actually - * not supported by BatchToolPanelCoordinator::profileChange! - */ -void BatchToolPanelCoordinator::profileChange (const rtengine::procparams::PartialProfile* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited) { - - if (event==rtengine::EvProfileChanged) { - // a profile has been selected in a hypothetical Profile panel - // -> ACTUALLY NOT SUPPORTED - return; - } - - pparams = *(nparams->pparams); - if (paramsEdited) - pparamsEdited = *paramsEdited; - - - for (size_t i=0; iread (&pparams, &pparamsEdited); - // I guess we don't want to automatically unfold curve editors here... - - somethingChanged = true; - - // read new values from the gui - for (size_t i=0; iwrite (&pparams, &pparamsEdited); - - // combine with initial parameters of each image and set - ProcParams newParams; - for (size_t i=0; isetProcParams (newParams, NULL, BATCHEDITOR, false); - } - - for (size_t i=0; iprocParamsChanged (&pparams, event, descr, &pparamsEdited); -} - -void BatchToolPanelCoordinator::cropSelectionReady () { - - toolBar->setTool (TMHand); -} - -CropGUIListener* BatchToolPanelCoordinator::startCropEditing (Thumbnail* thm) { - - if (thm) { - int w, h; - thm->getFinalSize (thm->getProcParams (), w, h); - crop->setDimensions (w, h); - } - return crop; -} - -void BatchToolPanelCoordinator::rotateSelectionReady (double rotate_deg, Thumbnail* thm) { - - toolBar->setTool (TMHand); - if (rotate_deg!=0.0) - rotate->straighten (rotate_deg); -} - -void BatchToolPanelCoordinator::spotWBselected (int x, int y, Thumbnail* thm) { - -// toolBar->setTool (TOOL_HAND); - if (x>0 && y>0 && thm) { - for (size_t i=0; igetSpotWB (x, y, whitebalance->getSize(), temp, green); - double otemp = initialPP[i].wb.temperature; - double ogreen = initialPP[i].wb.green; - if (options.baBehav[12]) - temp = temp - otemp; - if (options.baBehav[13]) - green = green - ogreen; - whitebalance->setWB (temp, green); - } - } -} - +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "multilangmgr.h" +#include "batchtoolpanelcoord.h" +#include "options.h" +#include "filepanel.h" +#include "procparamchangers.h" +#include "addsetids.h" + +using namespace rtengine::procparams; + +BatchToolPanelCoordinator::BatchToolPanelCoordinator (FilePanel* parent) : ToolPanelCoordinator(), somethingChanged(false), parent(parent) { + + blockedUpdate = false; + // remove exif panel and iptc panel + std::vector::iterator epi = std::find (toolPanels.begin(), toolPanels.end(), exifpanel); + if (epi!=toolPanels.end()) + toolPanels.erase (epi); + std::vector::iterator ipi = std::find (toolPanels.begin(), toolPanels.end(), iptcpanel); + if (ipi!=toolPanels.end()) + toolPanels.erase (ipi); + toolPanelNotebook->remove_page (*metadataPanel); + metadataPanel = 0; + toiM = 0; + + for (size_t i=0; isetBatchMode (true); +} + +void BatchToolPanelCoordinator::selectionChanged (const std::vector& selected) { + + if (selected!=this->selected) { + closeSession (); + this->selected = selected; + selFileNames.clear (); + for (size_t i=0; igetFileName ()); + initSession (); + } +} + +void BatchToolPanelCoordinator::closeSession (bool save) { + + pparamsEdited.set (false); + + for (size_t i=0; iremoveThumbnailListener (this); + + if (somethingChanged && save) { + + // read new values from the gui + for (size_t i=0; iwrite (&pparams, &pparamsEdited); + + // combine with initial parameters and set + ProcParams newParams; + for (size_t i=0; itrimValues (&newParams); + + selected[i]->setProcParams (newParams, NULL, BATCHEDITOR, true); + } + } + for (size_t i=0; iclearParamChanges (); +} + +void BatchToolPanelCoordinator::initSession () { + + somethingChanged = false; + + initialPP.resize (selected.size()); + for (size_t i=0; igetProcParams (); + selected[i]->applyAutoExp (initialPP[i]); + selected[i]->addThumbnailListener (this); + } + + // compare all the ProcParams and describe which parameters has different (i.e. inconsistent) values in pparamsEdited + pparamsEdited.initFrom (initialPP); + + crop->setDimensions (100000, 100000); + +/* if (!selected.empty()) { + pparams = selected[0]->getProcParams (); + for (int i=0; isetDefaults (&pparams, &pparamsEdited); + toolPanels[i]->read (&pparams, &pparamsEdited); + } + for (int i=0; iprocParamsChanged (&pparams, rtengine::EvPhotoLoaded, "batch processing", &pparamsEdited); + } +*/ + + if (!selected.empty()) { + + // The first selected image (in the thumbnail list, not the click list) is used to populate the EditorPanel and set the default values + pparams = selected[0]->getProcParams (); + + coarse->initBatchBehavior (); + + if (selected.size()==1) { + + for (size_t i=0; isetMultiImage(false); + + toneCurve->setAdjusterBehavior (false, false, false, false, false, false, false, false); + lcurve->setAdjusterBehavior (false, false, false); + whitebalance->setAdjusterBehavior (false, false, false); + vibrance->setAdjusterBehavior (false, false); + vignetting->setAdjusterBehavior (false, false, false, false); + colorappearance->setAdjusterBehavior (false, false, false, false, false, false, false, false, false, false, false, false, false); + rotate->setAdjusterBehavior (false); + distortion->setAdjusterBehavior (false); + perspective->setAdjusterBehavior (false); + gradient->setAdjusterBehavior (false, false, false, false); + pcvignette->setAdjusterBehavior (false, false, false); + cacorrection->setAdjusterBehavior (false); + sharpening->setAdjusterBehavior (false); + sharpenEdge->setAdjusterBehavior (false, false); + sharpenMicro->setAdjusterBehavior (false, false); + icm->setAdjusterBehavior (false, false); + + chmixer->setAdjusterBehavior (false); + blackwhite->setAdjusterBehavior (false,false); + colortoning->setAdjusterBehavior (false, false, false, false, false); + filmSimulation->setAdjusterBehavior(false); + + shadowshighlights->setAdjusterBehavior (false, false, false); + dirpyrequalizer->setAdjusterBehavior (false, false, false); + wavelet->setAdjusterBehavior (false, false, false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false, false, false); + dirpyrdenoise->setAdjusterBehavior (false, false,false,false,false,false, false); + bayerpreprocess->setAdjusterBehavior (false, false); + rawcacorrection->setAdjusterBehavior (false); + flatfield->setAdjusterBehavior(false); + rawexposure->setAdjusterBehavior (false, false); + bayerrawexposure->setAdjusterBehavior (false); + xtransrawexposure->setAdjusterBehavior (false); + } + else { + + for (size_t i=0; isetMultiImage(true); + + toneCurve->setAdjusterBehavior (options.baBehav[ADDSET_TC_EXPCOMP], options.baBehav[ADDSET_TC_HLCOMPAMOUNT],options.baBehav[ADDSET_TC_HLCOMPTHRESH], options.baBehav[ADDSET_TC_BRIGHTNESS], options.baBehav[ADDSET_TC_BLACKLEVEL],options.baBehav[ADDSET_TC_SHCOMP], options.baBehav[ADDSET_TC_CONTRAST], options.baBehav[ADDSET_TC_SATURATION]); + lcurve->setAdjusterBehavior (options.baBehav[ADDSET_LC_BRIGHTNESS], options.baBehav[ADDSET_LC_CONTRAST], options.baBehav[ADDSET_LC_CHROMATICITY]); + whitebalance->setAdjusterBehavior (options.baBehav[ADDSET_WB_TEMPERATURE], options.baBehav[ADDSET_WB_GREEN], options.baBehav[ADDSET_WB_EQUAL]); + vibrance->setAdjusterBehavior (options.baBehav[ADDSET_VIBRANCE_PASTELS], options.baBehav[ADDSET_VIBRANCE_SATURATED]); + vignetting->setAdjusterBehavior (options.baBehav[ADDSET_VIGN_AMOUNT], options.baBehav[ADDSET_VIGN_RADIUS], options.baBehav[ADDSET_VIGN_STRENGTH], options.baBehav[ADDSET_VIGN_CENTER]); + colorappearance->setAdjusterBehavior (options.baBehav[ADDSET_CAT_DEGREE], options.baBehav[ADDSET_CAT_ADAPTSCENE], options.baBehav[ADDSET_CAT_ADAPTVIEWING],options.baBehav[ADDSET_CAT_BADPIX], options.baBehav[ADDSET_CAT_LIGHT], options.baBehav[ADDSET_CAT_CHROMA],options.baBehav[ADDSET_CAT_CONTRAST],options.baBehav[ADDSET_CAT_RSTPRO],options.baBehav[ADDSET_CAT_BRIGHT],options.baBehav[ADDSET_CAT_CONTRAST_Q],options.baBehav[ADDSET_CAT_CHROMA_S],options.baBehav[ADDSET_CAT_CHROMA_M],options.baBehav[ADDSET_CAT_HUE]); + rotate->setAdjusterBehavior (options.baBehav[ADDSET_ROTATE_DEGREE]); + distortion->setAdjusterBehavior (options.baBehav[ADDSET_DIST_AMOUNT]); + perspective->setAdjusterBehavior (options.baBehav[ADDSET_PERSPECTIVE]); + gradient->setAdjusterBehavior (options.baBehav[ADDSET_GRADIENT_DEGREE], options.baBehav[ADDSET_GRADIENT_FEATHER], options.baBehav[ADDSET_GRADIENT_STRENGTH], options.baBehav[ADDSET_GRADIENT_CENTER]); + pcvignette->setAdjusterBehavior (options.baBehav[ADDSET_PCVIGNETTE_STRENGTH], options.baBehav[ADDSET_PCVIGNETTE_FEATHER], options.baBehav[ADDSET_PCVIGNETTE_ROUNDNESS]); + cacorrection->setAdjusterBehavior (options.baBehav[ADDSET_CA]); + sharpening->setAdjusterBehavior (options.baBehav[ADDSET_SHARP_AMOUNT]); + sharpenEdge->setAdjusterBehavior (options.baBehav[ADDSET_SHARPENEDGE_AMOUNT],options.baBehav[ADDSET_SHARPENEDGE_PASS]); + sharpenMicro->setAdjusterBehavior (options.baBehav[ADDSET_SHARPENMICRO_AMOUNT],options.baBehav[ADDSET_SHARPENMICRO_UNIFORMITY]); + icm->setAdjusterBehavior (options.baBehav[ADDSET_FREE_OUPUT_GAMMA],options.baBehav[ADDSET_FREE_OUTPUT_SLOPE]); +// colortoning->setAdjusterBehavior (options.baBehav[ADDSET_COLORTONING_SPLIT], options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD], options.baBehav[ADDSET_COLORTONING_SATOPACITY], options.baBehav[ADDSET_COLORTONING_STRPROTECT], options.baBehav[ADDSET_COLORTONING_BALANCE]); + colortoning->setAdjusterBehavior (options.baBehav[ADDSET_COLORTONING_SPLIT], options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD], options.baBehav[ADDSET_COLORTONING_SATOPACITY], options.baBehav[ADDSET_COLORTONING_STRENGTH], options.baBehav[ADDSET_COLORTONING_BALANCE]); + filmSimulation->setAdjusterBehavior(options.baBehav[ADDSET_FILMSIMULATION_STRENGTH]); + + chmixer->setAdjusterBehavior (options.baBehav[ADDSET_CHMIXER] ); + blackwhite->setAdjusterBehavior (options.baBehav[ADDSET_BLACKWHITE_HUES],options.baBehav[ADDSET_BLACKWHITE_GAMMA]); + shadowshighlights->setAdjusterBehavior (options.baBehav[ADDSET_SH_HIGHLIGHTS], options.baBehav[ADDSET_SH_SHADOWS], options.baBehav[ADDSET_SH_LOCALCONTRAST]); + dirpyrequalizer->setAdjusterBehavior (options.baBehav[ADDSET_DIRPYREQ], options.baBehav[ADDSET_DIRPYREQ_THRESHOLD], options.baBehav[ADDSET_DIRPYREQ_SKINPROTECT]); + wavelet->setAdjusterBehavior (options.baBehav[ADDSET_WA], options.baBehav[ADDSET_WA_THRESHOLD], options.baBehav[ADDSET_WA_THRESHOLD2],options.baBehav[ADDSET_WA_THRES],options.baBehav[ADDSET_WA_CHRO],options.baBehav[ADDSET_WA_CHROMA],options.baBehav[ADDSET_WA_CONTRAST],options.baBehav[ADDSET_WA_SKINPROTECT],options.baBehav[ADDSET_WA_RESCHRO],options.baBehav[ADDSET_WA_TMRS],options.baBehav[ADDSET_WA_RESCON],options.baBehav[ADDSET_WA_RESCONH],options.baBehav[ADDSET_WA_THRR],options.baBehav[ADDSET_WA_THRRH],options.baBehav[ADDSET_WA_SKYPROTECT], options.baBehav[ADDSET_WA_EDGRAD],options.baBehav[ADDSET_WA_EDGVAL],options.baBehav[ADDSET_WA_STRENGTH],options.baBehav[ADDSET_WA_GAMMA],options.baBehav[ADDSET_WA_EDGEDETECT], options.baBehav[ADDSET_WA_EDGEDETECTTHR], options.baBehav[ADDSET_WA_EDGEDETECTTHR2]); + dirpyrdenoise->setAdjusterBehavior (options.baBehav[ADDSET_DIRPYRDN_LUMA],options.baBehav[ADDSET_DIRPYRDN_LUMDET],options.baBehav[ADDSET_DIRPYRDN_CHROMA],options.baBehav[ADDSET_DIRPYRDN_CHROMARED],options.baBehav[ADDSET_DIRPYRDN_CHROMABLUE], options.baBehav[ADDSET_DIRPYRDN_GAMMA], options.baBehav[ADDSET_DIRPYRDN_PASSES]); + bayerpreprocess->setAdjusterBehavior (options.baBehav[ADDSET_PREPROCESS_LINEDENOISE], options.baBehav[ADDSET_PREPROCESS_GREENEQUIL]); + rawcacorrection->setAdjusterBehavior (options.baBehav[ADDSET_RAWCACORR]); + flatfield->setAdjusterBehavior(options.baBehav[ADDSET_RAWFFCLIPCONTROL]); + rawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_LINEAR], options.baBehav[ADDSET_RAWEXPOS_PRESER]); + bayerrawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_BLACKS]); + xtransrawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_BLACKS]); + + if (options.baBehav[ADDSET_TC_EXPCOMP]) pparams.toneCurve.expcomp = 0; + if (options.baBehav[ADDSET_TC_HLCOMPAMOUNT]) pparams.toneCurve.hlcompr = 0; + if (options.baBehav[ADDSET_TC_HLCOMPTHRESH]) pparams.toneCurve.hlcomprthresh = 0; + if (options.baBehav[ADDSET_TC_BRIGHTNESS]) pparams.toneCurve.brightness = 0; + if (options.baBehav[ADDSET_TC_BLACKLEVEL]) pparams.toneCurve.black = 0; + if (options.baBehav[ADDSET_TC_SHCOMP]) pparams.toneCurve.shcompr = 0; + if (options.baBehav[ADDSET_TC_CONTRAST]) pparams.toneCurve.contrast = 0; + + if (options.baBehav[ADDSET_SH_HIGHLIGHTS]) pparams.sh.highlights = 0; + if (options.baBehav[ADDSET_SH_SHADOWS]) pparams.sh.shadows = 0; + if (options.baBehav[ADDSET_SH_LOCALCONTRAST]) pparams.sh.localcontrast = 0; + + if (options.baBehav[ADDSET_LC_BRIGHTNESS]) pparams.labCurve.brightness = 0; + if (options.baBehav[ADDSET_LC_CONTRAST]) pparams.labCurve.contrast = 0; + if (options.baBehav[ADDSET_LC_CHROMATICITY]) pparams.labCurve.chromaticity = 0; + + if (options.baBehav[ADDSET_SHARP_AMOUNT]) pparams.sharpening.amount = 0; + if (options.baBehav[ADDSET_SHARPENEDGE_AMOUNT]) pparams.sharpenEdge.amount = 0; + if (options.baBehav[ADDSET_SHARPENMICRO_AMOUNT]) pparams.sharpenMicro.amount = 0; + if (options.baBehav[ADDSET_SHARPENEDGE_PASS]) pparams.sharpenEdge.passes = 0; + if (options.baBehav[ADDSET_SHARPENMICRO_UNIFORMITY]) pparams.sharpenMicro.uniformity = 0; + + if (options.baBehav[ADDSET_CHMIXER]) for (int i=0; i<3; i++) pparams.chmixer.red[i] = pparams.chmixer.green[i] = pparams.chmixer.blue[i] = 0; + if (options.baBehav[ADDSET_BLACKWHITE_HUES]) pparams.blackwhite.mixerRed=pparams.blackwhite.mixerOrange=pparams.blackwhite.mixerYellow= + pparams.blackwhite.mixerGreen=pparams.blackwhite.mixerCyan=pparams.blackwhite.mixerBlue= + pparams.blackwhite.mixerMagenta=pparams.blackwhite.mixerPurple=0; + if (options.baBehav[ADDSET_BLACKWHITE_GAMMA]) pparams.blackwhite.gammaRed=pparams.blackwhite.gammaGreen=pparams.blackwhite.gammaBlue = 0; + + //if (options.baBehav[ADDSET_LD_EDGETOLERANCE]) pparams.lumaDenoise.edgetolerance = 0; + + if (options.baBehav[ADDSET_WB_TEMPERATURE]) pparams.wb.temperature = 0; + if (options.baBehav[ADDSET_WB_GREEN]) pparams.wb.green = 0; + if (options.baBehav[ADDSET_WB_EQUAL]) pparams.wb.equal = 0; + + if (options.baBehav[ADDSET_VIBRANCE_PASTELS]) pparams.vibrance.pastels = 0; + if (options.baBehav[ADDSET_VIBRANCE_SATURATED]) pparams.vibrance.saturated = 0; + + if (options.baBehav[ADDSET_CAT_DEGREE]) pparams.colorappearance.degree = 0; + if (options.baBehav[ADDSET_CAT_ADAPTSCENE]) pparams.colorappearance.adapscen = 0; + if (options.baBehav[ADDSET_CAT_ADAPTVIEWING]) pparams.colorappearance.adaplum = 0; + if (options.baBehav[ADDSET_CAT_BADPIX]) pparams.colorappearance.badpixsl = 0; + if (options.baBehav[ADDSET_CAT_LIGHT]) pparams.colorappearance.jlight = 0; + if (options.baBehav[ADDSET_CAT_BRIGHT]) pparams.colorappearance.qbright = 0; + if (options.baBehav[ADDSET_CAT_CHROMA]) pparams.colorappearance.chroma = 0; + if (options.baBehav[ADDSET_CAT_CHROMA_S]) pparams.colorappearance.schroma = 0; + if (options.baBehav[ADDSET_CAT_CHROMA_M]) pparams.colorappearance.mchroma = 0; + if (options.baBehav[ADDSET_CAT_RSTPRO]) pparams.colorappearance.rstprotection = 0; + if (options.baBehav[ADDSET_CAT_CONTRAST]) pparams.colorappearance.contrast = 0; + if (options.baBehav[ADDSET_CAT_CONTRAST_Q]) pparams.colorappearance.qcontrast = 0; + if (options.baBehav[ADDSET_CAT_HUE]) pparams.colorappearance.colorh = 0; + + if (options.baBehav[ADDSET_FREE_OUPUT_GAMMA]) pparams.icm.gampos = 0; + if (options.baBehav[ADDSET_FREE_OUTPUT_SLOPE]) pparams.icm.slpos = 0; + + //if (options.baBehav[ADDSET_CBOOST_AMOUNT]) pparams.colorBoost.amount = 0; + + //if (options.baBehav[ADDSET_CS_BLUEYELLOW]) pparams.colorShift.a = 0; + //if (options.baBehav[ADDSET_CS_GREENMAGENTA]) pparams.colorShift.b = 0; + if (options.baBehav[ADDSET_COLORTONING_SPLIT]) pparams.colorToning.redlow = pparams.colorToning.greenlow = pparams.colorToning.bluelow = + pparams.colorToning.redmed = pparams.colorToning.greenmed = pparams.colorToning.bluemed = + pparams.colorToning.redhigh = pparams.colorToning.greenhigh = pparams.colorToning.bluehigh = + pparams.colorToning.satlow = pparams.colorToning.sathigh = 0; + if (options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD]) pparams.colorToning.satProtectionThreshold = 0; + if (options.baBehav[ADDSET_COLORTONING_SATOPACITY]) pparams.colorToning.saturatedOpacity = 0; + if (options.baBehav[ADDSET_COLORTONING_BALANCE]) pparams.colorToning.balance = 0; + if (options.baBehav[ADDSET_COLORTONING_STRENGTH]) pparams.colorToning.strength = 0; + + if (options.baBehav[ADDSET_FILMSIMULATION_STRENGTH]) pparams.filmSimulation.strength = 0; + + if (options.baBehav[ADDSET_ROTATE_DEGREE]) pparams.rotate.degree = 0; + if (options.baBehav[ADDSET_DIST_AMOUNT]) pparams.distortion.amount = 0; + if (options.baBehav[ADDSET_PERSPECTIVE]) pparams.perspective.horizontal = pparams.perspective.vertical = 0; + if (options.baBehav[ADDSET_GRADIENT_DEGREE]) pparams.gradient.degree = 0; + if (options.baBehav[ADDSET_GRADIENT_FEATHER]) pparams.gradient.feather = 0; + if (options.baBehav[ADDSET_GRADIENT_STRENGTH]) pparams.gradient.strength = 0; + if (options.baBehav[ADDSET_GRADIENT_CENTER]) pparams.gradient.centerX = 0; + if (options.baBehav[ADDSET_GRADIENT_CENTER]) pparams.gradient.centerY = 0; + if (options.baBehav[ADDSET_PCVIGNETTE_STRENGTH]) pparams.pcvignette.strength = 0; + if (options.baBehav[ADDSET_PCVIGNETTE_FEATHER]) pparams.pcvignette.feather = 0; + if (options.baBehav[ADDSET_PCVIGNETTE_ROUNDNESS]) pparams.pcvignette.roundness = 0; + if (options.baBehav[ADDSET_CA]) pparams.cacorrection.red = 0; + if (options.baBehav[ADDSET_CA]) pparams.cacorrection.blue = 0; + if (options.baBehav[ADDSET_VIGN_AMOUNT]) pparams.vignetting.amount = 0; + if (options.baBehav[ADDSET_VIGN_RADIUS]) pparams.vignetting.radius = 0; + if (options.baBehav[ADDSET_VIGN_STRENGTH]) pparams.vignetting.strength = 0; + if (options.baBehav[ADDSET_VIGN_CENTER]) pparams.vignetting.centerX = 0; + if (options.baBehav[ADDSET_VIGN_CENTER]) pparams.vignetting.centerY = 0; + + if (options.baBehav[ADDSET_DIRPYREQ]) for (int i=0; i<6; i++) pparams.dirpyrequalizer.mult[i] = 0; + if (options.baBehav[ADDSET_DIRPYREQ_THRESHOLD]) pparams.dirpyrequalizer.threshold = 0; + if (options.baBehav[ADDSET_DIRPYREQ_SKINPROTECT]) pparams.dirpyrequalizer.skinprotect = 0; + + if (options.baBehav[ADDSET_WA]) for (int i=0; i<8; i++) pparams.wavelet.c[i] = 0; + if (options.baBehav[ADDSET_WA_THRESHOLD]) pparams.wavelet.threshold = 0; + if (options.baBehav[ADDSET_WA_THRESHOLD2]) pparams.wavelet.threshold2 = 0; + if (options.baBehav[ADDSET_WA_SKINPROTECT]) pparams.wavelet.skinprotect = 0; + if (options.baBehav[ADDSET_WA_CHRO]) pparams.wavelet.chro = 0; + if (options.baBehav[ADDSET_WA_CHROMA]) pparams.wavelet.chroma = 0; + if (options.baBehav[ADDSET_WA_CONTRAST]) pparams.wavelet.contrast = 0; + if (options.baBehav[ADDSET_WA_THRES]) pparams.wavelet.thres = 0; + if (options.baBehav[ADDSET_WA_RESCON]) pparams.wavelet.rescon = 0; + if (options.baBehav[ADDSET_WA_RESCONH]) pparams.wavelet.resconH = 0; + if (options.baBehav[ADDSET_WA_RESCHRO]) pparams.wavelet.reschro = 0; + if (options.baBehav[ADDSET_WA_TMRS]) pparams.wavelet.tmrs = 0; + if (options.baBehav[ADDSET_WA_THRR]) pparams.wavelet.thr = 0; + if (options.baBehav[ADDSET_WA_THRRH]) pparams.wavelet.thrH = 0; + if (options.baBehav[ADDSET_WA_SKYPROTECT]) pparams.wavelet.sky = 0; + if (options.baBehav[ADDSET_WA_EDGRAD]) pparams.wavelet.edgrad = 0; + if (options.baBehav[ADDSET_WA_EDGVAL]) pparams.wavelet.edgval = 0; + if (options.baBehav[ADDSET_WA_STRENGTH]) pparams.wavelet.strength = 0; + if (options.baBehav[ADDSET_WA_EDGEDETECT]) pparams.wavelet.edgedetect = 0; + if (options.baBehav[ADDSET_WA_GAMMA]) pparams.wavelet.gamma = 0; + + + if (options.baBehav[ADDSET_DIRPYRDN_LUMA]) pparams.dirpyrDenoise.luma = 0; + + if (options.baBehav[ADDSET_DIRPYRDN_CHROMA]) pparams.dirpyrDenoise.chroma = 0; + if (options.baBehav[ADDSET_DIRPYRDN_CHROMARED]) pparams.dirpyrDenoise.redchro = 0; + if (options.baBehav[ADDSET_DIRPYRDN_CHROMABLUE]) pparams.dirpyrDenoise.bluechro = 0; +// pparams.dirpyrDenoise.Ldetail = pparams.dirpyrDenoise.luma = pparams.dirpyrDenoise.chroma = 0; + if (options.baBehav[ADDSET_DIRPYRDN_GAMMA]) pparams.dirpyrDenoise.gamma = 0; + + if (options.baBehav[ADDSET_RAWCACORR]) pparams.raw.cablue = pparams.raw.cared = 0; + if (options.baBehav[ADDSET_RAWEXPOS_LINEAR]) pparams.raw.expos = 0; + if (options.baBehav[ADDSET_RAWEXPOS_PRESER]) pparams.raw.preser = 0; + if (options.baBehav[ADDSET_RAWEXPOS_BLACKS]) { + pparams.raw.bayersensor.black0 = pparams.raw.bayersensor.black1 = pparams.raw.bayersensor.black2 = pparams.raw.bayersensor.black3 = 0; + pparams.raw.xtranssensor.blackred = pparams.raw.xtranssensor.blackgreen = pparams.raw.xtranssensor.blackblue = 0; + } + if (options.baBehav[ADDSET_RAWFFCLIPCONTROL]) pparams.raw.ff_clipControl = 0; + + if (options.baBehav[ADDSET_PREPROCESS_GREENEQUIL]) pparams.raw.bayersensor.greenthresh = 0; + if (options.baBehav[ADDSET_PREPROCESS_LINEDENOISE]) pparams.raw.bayersensor.linenoise = 0; + } + + for (size_t i=0; isetDefaults (&pparams, &pparamsEdited); + toolPanels[i]->read (&pparams, &pparamsEdited); + // TODO: autoOpenCurve has been disabled because initSession is called on each parameter change from the editor panel, + // if the thumbnail remains selected in the DirectoryBrowser (i.e. always, unless the user think about deselecting it) + //toolPanels[i]->autoOpenCurve(); + } + for (size_t i=0; iprocParamsChanged (&pparams, rtengine::EvPhotoLoaded, M("BATCH_PROCESSING"), &pparamsEdited); + } +} + +void BatchToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr) { + + if (selected.empty()) + return; + + somethingChanged = true; + + pparamsEdited.set (false); + // read new values from the gui + for (size_t i=0; iwrite (&pparams, &pparamsEdited); + + // If only a single item is selected, we emulate the behaviour of the editor tool panel coordinator, + // otherwise we adjust the inital parameters on a per-image basis. + if (selected.size()==1) { + // Compensate rotation on flip + if (event==rtengine::EvCTHFlip || event==rtengine::EvCTVFlip) { + if (fabs(pparams.rotate.degree)>0.001) { + pparams.rotate.degree *= -1; + rotate->read (&pparams); + } + } + + int w, h; + selected[0]->getFinalSize (selected[0]->getProcParams (), w, h); + crop->setDimensions(w, h); + + // Some transformations change the crop and resize parameter for convenience. + if (event==rtengine::EvCTHFlip) { + crop->hFlipCrop (); + crop->write (&pparams, &pparamsEdited); + } + else if (event==rtengine::EvCTVFlip) { + crop->vFlipCrop (); + crop->write (&pparams, &pparamsEdited); + } + else if (event==rtengine::EvCTRotate) { + crop->rotateCrop (pparams.coarse.rotate, pparams.coarse.hflip, pparams.coarse.vflip); + crop->write (&pparams, &pparamsEdited); + resize->update (pparams.crop.enabled, pparams.crop.w, pparams.crop.h, w, h); + resize->write (&pparams, &pparamsEdited); + } + else if (event==rtengine::EvCrop) { + resize->update (pparams.crop.enabled, pparams.crop.w, pparams.crop.h); + resize->write (&pparams, &pparamsEdited); + } + } + else { + // Compensate rotation on flip + if (event==rtengine::EvCTHFlip || event==rtengine::EvCTVFlip) { + for (size_t i=0; i 0.001) { + initialPP[i].rotate.degree *= -1.0; + + pparamsEdited.rotate.degree = false; + } + } + } + + // some transformations make the crop change for convenience + if (event==rtengine::EvCTHFlip) { + for (size_t i=0; igetFinalSize (selected[i]->getProcParams (), w, h); + + rtengine::procparams::CropParams& crop = initialPP[i].crop; + crop.x = w - crop.x - crop.w; + + pparamsEdited.crop.x = false; + } + } + else if (event==rtengine::EvCTVFlip) { + for (size_t i=0; igetFinalSize (selected[i]->getProcParams (), w, h); + + rtengine::procparams::CropParams& crop = initialPP[i].crop; + crop.y = h - crop.y - crop.h; + + pparamsEdited.crop.y = false; + } + } + else if (event==rtengine::EvCTRotate) { + int newDeg = pparams.coarse.rotate; + for (size_t i=0; igetFinalSize (selected[i]->getProcParams (), w, h); + + int oldDeg = initialPP[i].coarse.rotate; + + rtengine::procparams::CropParams& crop = initialPP[i].crop; + int rotation = (360 + newDeg - oldDeg) % 360; + ProcParams pptemp = selected[i]->getProcParams(); // Get actual procparams + if((pptemp.coarse.hflip != pptemp.coarse.vflip) && ((rotation%180)==90)) + rotation = (rotation + 180)%360; + + + switch (rotation) { + case 90: + std::swap(crop.x, crop.y); + std::swap(crop.w, crop.h); + + crop.x = h - crop.x - crop.w; + break; + case 270: + std::swap(crop.x, crop.y); + std::swap(crop.w, crop.h); + + crop.y = w - crop.y - crop.h; + break; + case 180: + crop.x = w - crop.x - crop.w; + crop.y = h - crop.y - crop.h; + break; + } + + initialPP[i].coarse.rotate = newDeg; + + } + pparamsEdited.crop.x = false; + pparamsEdited.crop.y = false; + pparamsEdited.crop.w = false; + pparamsEdited.crop.h = false; + pparamsEdited.coarse.rotate = false; + } + } + + if (event==rtengine::EvAutoExp || event==rtengine::EvClip) + for (size_t i=0; iapplyAutoExp (initialPP[i]); + } + + if (event==rtengine::EvAutoDIST) { + for (size_t i=0; itrimValues (&newParams); + + selected[i]->setProcParams (newParams, NULL, BATCHEDITOR, false); + } + + for (size_t i=0; iprocParamsChanged (&pparams, event, descr, &pparamsEdited); +} + +void BatchToolPanelCoordinator::getAutoWB (double& temp, double& green, double equal) { + + if (!selected.empty()) + selected[0]->getAutoWB (temp, green, equal); +} + +void BatchToolPanelCoordinator::getCamWB (double& temp, double& green) { + + if (!selected.empty()) + selected[0]->getCamWB (temp, green); +} + +void BatchToolPanelCoordinator::optionsChanged () { + + closeSession (); + initSession (); +} + +void BatchToolPanelCoordinator::procParamsChanged (Thumbnail* thm, int whoChangedIt) { + + if (whoChangedIt!=BATCHEDITOR && !blockedUpdate) { + closeSession (false); + initSession (); + } +} + +void BatchToolPanelCoordinator::beginBatchPParamsChange(int numberOfEntries) { + + blockedUpdate = true; + if (numberOfEntries > 50) // Arbitrary amount + parent->set_sensitive(false); +} + +// The end of a batch pparams change triggers a close/initsession +void BatchToolPanelCoordinator::endBatchPParamsChange() { + //printf("BatchToolPanelCoordinator::endBatchPParamsChange / Nouvelle session!\n"); + closeSession (false); + initSession (); + blockedUpdate = false; + parent->set_sensitive(true); +} + +/* + * WARNING: profileChange is actually called by the History only. + * Using a Profile panel in the batch tool panel editor is actually + * not supported by BatchToolPanelCoordinator::profileChange! + */ +void BatchToolPanelCoordinator::profileChange (const rtengine::procparams::PartialProfile* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited) { + + if (event==rtengine::EvProfileChanged) { + // a profile has been selected in a hypothetical Profile panel + // -> ACTUALLY NOT SUPPORTED + return; + } + + pparams = *(nparams->pparams); + if (paramsEdited) + pparamsEdited = *paramsEdited; + + + for (size_t i=0; iread (&pparams, &pparamsEdited); + // I guess we don't want to automatically unfold curve editors here... + + somethingChanged = true; + + // read new values from the gui + for (size_t i=0; iwrite (&pparams, &pparamsEdited); + + // combine with initial parameters of each image and set + ProcParams newParams; + for (size_t i=0; isetProcParams (newParams, NULL, BATCHEDITOR, false); + } + + for (size_t i=0; iprocParamsChanged (&pparams, event, descr, &pparamsEdited); +} + +void BatchToolPanelCoordinator::cropSelectionReady () { + + toolBar->setTool (TMHand); +} + +CropGUIListener* BatchToolPanelCoordinator::startCropEditing (Thumbnail* thm) { + + if (thm) { + int w, h; + thm->getFinalSize (thm->getProcParams (), w, h); + crop->setDimensions (w, h); + } + return crop; +} + +void BatchToolPanelCoordinator::rotateSelectionReady (double rotate_deg, Thumbnail* thm) { + + toolBar->setTool (TMHand); + if (rotate_deg!=0.0) + rotate->straighten (rotate_deg); +} + +void BatchToolPanelCoordinator::spotWBselected (int x, int y, Thumbnail* thm) { + +// toolBar->setTool (TOOL_HAND); + if (x>0 && y>0 && thm) { + for (size_t i=0; igetSpotWB (x, y, whitebalance->getSize(), temp, green); + double otemp = initialPP[i].wb.temperature; + double ogreen = initialPP[i].wb.green; + if (options.baBehav[12]) + temp = temp - otemp; + if (options.baBehav[13]) + green = green - ogreen; + whitebalance->setWB (temp, green); + } + } +} + diff --git a/rtgui/bayerpreprocess.h b/rtgui/bayerpreprocess.h index 5c2ec4cdb..a6e46bc7d 100644 --- a/rtgui/bayerpreprocess.h +++ b/rtgui/bayerpreprocess.h @@ -1,49 +1,49 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _BAYERPREPROCESS_H_ -#define _BAYERPREPROCESS_H_ - -#include -#include "adjuster.h" -#include "toolpanel.h" -#include "../rtengine/rawimage.h" - -class BayerPreProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { - - protected: - - Adjuster* lineDenoise; - Adjuster* greenEqThreshold; - - public: - - BayerPreProcess (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - - void adjusterChanged (Adjuster* a, double newval); - void hotDeadPixelChanged(); - void setAdjusterBehavior (bool linedenoiseadd, bool greenequiladd); - void trimValues (rtengine::procparams::ProcParams* pp); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _BAYERPREPROCESS_H_ +#define _BAYERPREPROCESS_H_ + +#include +#include "adjuster.h" +#include "toolpanel.h" +#include "../rtengine/rawimage.h" + +class BayerPreProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { + + protected: + + Adjuster* lineDenoise; + Adjuster* greenEqThreshold; + + public: + + BayerPreProcess (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + + void adjusterChanged (Adjuster* a, double newval); + void hotDeadPixelChanged(); + void setAdjusterBehavior (bool linedenoiseadd, bool greenequiladd); + void trimValues (rtengine::procparams::ProcParams* pp); +}; + +#endif diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 9a8b49329..f60b0d1ee 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -1,270 +1,270 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "bayerprocess.h" -#include "options.h" -#include "guiutils.h" -using namespace rtengine; -using namespace rtengine::procparams; - -BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RAW_LABEL"), true) -{ - Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); - hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4); - method = Gtk::manage (new MyComboBoxText ()); - for( size_t i=0; iappend_text(procparams::RAWParams::BayerSensor::methodstring[i]); - - method->set_active(0); - hb1->set_tooltip_markup (M("TP_RAW_DMETHOD_TOOLTIP")); - - hb1->pack_end (*method, Gtk::PACK_EXPAND_WIDGET, 4); - pack_start( *hb1, Gtk::PACK_SHRINK, 4); - - dcbOptions = Gtk::manage (new Gtk::VBox ()); - dcbOptions->set_border_width(4); - - dcbIterations = Gtk::manage (new Adjuster (M("TP_RAW_DCBITERATIONS"),0,5,1,2)); - dcbIterations->setAdjusterListener (this); - if (dcbIterations->delay < 1000) dcbIterations->delay = 1000; - dcbIterations->show(); - dcbEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_DCBENHANCE"))); - dcbOptions->pack_start(*dcbIterations); - dcbOptions->pack_start(*dcbEnhance); - pack_start( *dcbOptions, Gtk::PACK_SHRINK, 4); - - lmmseOptions = Gtk::manage (new Gtk::VBox ()); - lmmseOptions->set_border_width(4); - - lmmseIterations = Gtk::manage (new Adjuster (M("TP_RAW_LMMSEITERATIONS"),0,6,1,2)); - lmmseIterations->setAdjusterListener (this); - lmmseIterations->set_tooltip_markup (M("TP_RAW_LMMSE_TOOLTIP")); - - if (lmmseIterations->delay < 1000) lmmseIterations->delay = 1000; - lmmseIterations->show(); - lmmseOptions->pack_start(*lmmseIterations); - pack_start( *lmmseOptions, Gtk::PACK_SHRINK, 4); - - pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); - ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"),0,5,1,0 )); - ccSteps->setAdjusterListener (this); - if (ccSteps->delay < 1000) ccSteps->delay = 1000; - ccSteps->show(); - pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); - - //pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); - //allOptions = Gtk::manage (new Gtk::VBox ()); - //allOptions->set_border_width(2); - //allEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_ALLENHANCE"))); - //allOptions->pack_start(*allEnhance); - //pack_start( *allOptions, Gtk::PACK_SHRINK, 4); - - methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::methodChanged) ); - dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true); - //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); -} - - -void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - methodconn.block (true); - dcbEnhconn.block (true); - //allEnhconn.block (true); - - method->set_active(procparams::RAWParams::BayerSensor::numMethods); - for( size_t i=0; i< procparams::RAWParams::BayerSensor::numMethods; i++) - if( pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[i]){ - method->set_active(i); - oldSelection = i; - break; - } - - if(pedited ){ - ccSteps->setEditedState (pedited->raw.bayersensor.ccSteps ? Edited : UnEdited); - dcbIterations->setEditedState ( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); - dcbEnhance->set_inconsistent(!pedited->raw.bayersensor.dcbEnhance); - //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); - lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); - - if( !pedited->raw.bayersensor.method ) - method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name - } - - //allEnhance->set_active(pp->raw.bayersensor.all_enhance); - - dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations); - dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance); - ccSteps->setValue (pp->raw.bayersensor.ccSteps); - if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] || - method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) - dcbOptions->show(); - else - dcbOptions->hide(); - - lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); - if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::lmmse] || - method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) - lmmseOptions->show(); - else - lmmseOptions->hide(); - - // Flase color suppression is applied to all demozaicing method, so don't hide anything - /*if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::eahd] || - pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::hphd] || - pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::vng4]) - ccSteps->show(); - else - ccSteps->hide();*/ - - lastDCBen = pp->raw.bayersensor.dcb_enhance; - //lastALLen = pp->raw.bayersensor.all_enhance; - - methodconn.block (false); - dcbEnhconn.block (false); - //allEnhconn.block (false); - - enableListener (); -} - -void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.bayersensor.ccSteps = ccSteps->getIntValue(); - pp->raw.bayersensor.dcb_iterations = dcbIterations->getIntValue(); - pp->raw.bayersensor.dcb_enhance = dcbEnhance->get_active(); - //pp->raw.bayersensor.all_enhance = allEnhance->get_active(); - pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); - - int currentRow = method->get_active_row_number(); - if( currentRow>=0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) - pp->raw.bayersensor.method = procparams::RAWParams::BayerSensor::methodstring[currentRow]; - - if (pedited) { - pedited->raw.bayersensor.ccSteps = ccSteps->getEditedState (); - pedited->raw.bayersensor.method = method->get_active_row_number() != procparams::RAWParams::BayerSensor::numMethods; - pedited->raw.bayersensor.dcbIterations = dcbIterations->getEditedState (); - pedited->raw.bayersensor.dcbEnhance = !dcbEnhance->get_inconsistent(); - //pedited->raw.bayersensor.allEnhance = !allEnhance->get_inconsistent(); - pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); - - } -} - -void BayerProcess::setBatchMode(bool batchMode) -{ - method->append_text (M("GENERAL_UNCHANGED")); - method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name - dcbOptions->hide(); - lmmseOptions->hide(); - ToolPanel::setBatchMode (batchMode); - ccSteps->showEditedCB (); - dcbIterations->showEditedCB (); - lmmseIterations->showEditedCB (); -} - -void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) -{ - dcbIterations->setDefault( defParams->raw.bayersensor.dcb_iterations); - lmmseIterations->setDefault( defParams->raw.bayersensor.lmmse_iterations); - ccSteps->setDefault (defParams->raw.bayersensor.ccSteps); - if (pedited) { - dcbIterations->setDefaultEditedState( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); - lmmseIterations->setDefaultEditedState( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); - ccSteps->setDefaultEditedState(pedited->raw.bayersensor.ccSteps ? Edited : UnEdited); - }else{ - dcbIterations->setDefaultEditedState( Irrelevant ); - lmmseIterations->setDefaultEditedState( Irrelevant ); - ccSteps->setDefaultEditedState(Irrelevant ); - } -} - -void BayerProcess::adjusterChanged (Adjuster* a, double newval) -{ - if (listener) { - if (a == dcbIterations) - listener->panelChanged (EvDemosaicDCBIter, a->getTextValue() ); - else if (a == ccSteps) - listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); - else if (a == lmmseIterations) - listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() ); - } -} - -void BayerProcess::methodChanged () -{ - int curSelection = method->get_active_row_number(); - if ( curSelection == procparams::RAWParams::BayerSensor::dcb){ - dcbOptions->show(); - }else{ - dcbOptions->hide(); - } - if ( curSelection == procparams::RAWParams::BayerSensor::lmmse){ - lmmseOptions->show(); - }else{ - lmmseOptions->hide(); - } - - Glib::ustring methodName=""; - bool ppreq = false; - if( curSelection>=0 && curSelection < procparams::RAWParams::BayerSensor::numMethods) { - methodName = procparams::RAWParams::BayerSensor::methodstring[curSelection]; - if (curSelection == procparams::RAWParams::BayerSensor::mono || oldSelection == procparams::RAWParams::BayerSensor::mono) { - ppreq = true; - } - } - oldSelection = curSelection; - - if (listener) - listener->panelChanged (ppreq ? EvDemosaicMethodPreProc : EvDemosaicMethod, methodName); -} - -void BayerProcess::dcbEnhanceChanged () -{ - if (batchMode) { - if (dcbEnhance->get_inconsistent()) { - dcbEnhance->set_inconsistent (false); - dcbEnhconn.block (true); - dcbEnhance->set_active (false); - dcbEnhconn.block (false); - } - else if (lastDCBen) - dcbEnhance->set_inconsistent (true); - - lastDCBen = dcbEnhance->get_active (); - } - if (listener) - listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); -} - -/*void BayerProcess::allEnhanceChanged () -{ - if (batchMode) { - if (allEnhance->get_inconsistent()) { - allEnhance->set_inconsistent (false); - allEnhconn.block (true); - allEnhance->set_active (false); - allEnhconn.block (false); - } - else if (lastALLen) - allEnhance->set_inconsistent (true); - - lastALLen = allEnhance->get_active (); - } - if (listener) - listener->panelChanged (EvDemosaicALLEnhanced, allEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); -}*/ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "bayerprocess.h" +#include "options.h" +#include "guiutils.h" +using namespace rtengine; +using namespace rtengine::procparams; + +BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RAW_LABEL"), true) +{ + Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); + hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4); + method = Gtk::manage (new MyComboBoxText ()); + for( size_t i=0; iappend_text(procparams::RAWParams::BayerSensor::methodstring[i]); + + method->set_active(0); + hb1->set_tooltip_markup (M("TP_RAW_DMETHOD_TOOLTIP")); + + hb1->pack_end (*method, Gtk::PACK_EXPAND_WIDGET, 4); + pack_start( *hb1, Gtk::PACK_SHRINK, 4); + + dcbOptions = Gtk::manage (new Gtk::VBox ()); + dcbOptions->set_border_width(4); + + dcbIterations = Gtk::manage (new Adjuster (M("TP_RAW_DCBITERATIONS"),0,5,1,2)); + dcbIterations->setAdjusterListener (this); + if (dcbIterations->delay < 1000) dcbIterations->delay = 1000; + dcbIterations->show(); + dcbEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_DCBENHANCE"))); + dcbOptions->pack_start(*dcbIterations); + dcbOptions->pack_start(*dcbEnhance); + pack_start( *dcbOptions, Gtk::PACK_SHRINK, 4); + + lmmseOptions = Gtk::manage (new Gtk::VBox ()); + lmmseOptions->set_border_width(4); + + lmmseIterations = Gtk::manage (new Adjuster (M("TP_RAW_LMMSEITERATIONS"),0,6,1,2)); + lmmseIterations->setAdjusterListener (this); + lmmseIterations->set_tooltip_markup (M("TP_RAW_LMMSE_TOOLTIP")); + + if (lmmseIterations->delay < 1000) lmmseIterations->delay = 1000; + lmmseIterations->show(); + lmmseOptions->pack_start(*lmmseIterations); + pack_start( *lmmseOptions, Gtk::PACK_SHRINK, 4); + + pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); + ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"),0,5,1,0 )); + ccSteps->setAdjusterListener (this); + if (ccSteps->delay < 1000) ccSteps->delay = 1000; + ccSteps->show(); + pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); + + //pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); + //allOptions = Gtk::manage (new Gtk::VBox ()); + //allOptions->set_border_width(2); + //allEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_ALLENHANCE"))); + //allOptions->pack_start(*allEnhance); + //pack_start( *allOptions, Gtk::PACK_SHRINK, 4); + + methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::methodChanged) ); + dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true); + //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true); +} + + +void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + methodconn.block (true); + dcbEnhconn.block (true); + //allEnhconn.block (true); + + method->set_active(procparams::RAWParams::BayerSensor::numMethods); + for( size_t i=0; i< procparams::RAWParams::BayerSensor::numMethods; i++) + if( pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[i]){ + method->set_active(i); + oldSelection = i; + break; + } + + if(pedited ){ + ccSteps->setEditedState (pedited->raw.bayersensor.ccSteps ? Edited : UnEdited); + dcbIterations->setEditedState ( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); + dcbEnhance->set_inconsistent(!pedited->raw.bayersensor.dcbEnhance); + //allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance); + lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); + + if( !pedited->raw.bayersensor.method ) + method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name + } + + //allEnhance->set_active(pp->raw.bayersensor.all_enhance); + + dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations); + dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance); + ccSteps->setValue (pp->raw.bayersensor.ccSteps); + if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] || + method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) + dcbOptions->show(); + else + dcbOptions->hide(); + + lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); + if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::lmmse] || + method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods) + lmmseOptions->show(); + else + lmmseOptions->hide(); + + // Flase color suppression is applied to all demozaicing method, so don't hide anything + /*if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::eahd] || + pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::hphd] || + pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::vng4]) + ccSteps->show(); + else + ccSteps->hide();*/ + + lastDCBen = pp->raw.bayersensor.dcb_enhance; + //lastALLen = pp->raw.bayersensor.all_enhance; + + methodconn.block (false); + dcbEnhconn.block (false); + //allEnhconn.block (false); + + enableListener (); +} + +void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.bayersensor.ccSteps = ccSteps->getIntValue(); + pp->raw.bayersensor.dcb_iterations = dcbIterations->getIntValue(); + pp->raw.bayersensor.dcb_enhance = dcbEnhance->get_active(); + //pp->raw.bayersensor.all_enhance = allEnhance->get_active(); + pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); + + int currentRow = method->get_active_row_number(); + if( currentRow>=0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) + pp->raw.bayersensor.method = procparams::RAWParams::BayerSensor::methodstring[currentRow]; + + if (pedited) { + pedited->raw.bayersensor.ccSteps = ccSteps->getEditedState (); + pedited->raw.bayersensor.method = method->get_active_row_number() != procparams::RAWParams::BayerSensor::numMethods; + pedited->raw.bayersensor.dcbIterations = dcbIterations->getEditedState (); + pedited->raw.bayersensor.dcbEnhance = !dcbEnhance->get_inconsistent(); + //pedited->raw.bayersensor.allEnhance = !allEnhance->get_inconsistent(); + pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); + + } +} + +void BayerProcess::setBatchMode(bool batchMode) +{ + method->append_text (M("GENERAL_UNCHANGED")); + method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name + dcbOptions->hide(); + lmmseOptions->hide(); + ToolPanel::setBatchMode (batchMode); + ccSteps->showEditedCB (); + dcbIterations->showEditedCB (); + lmmseIterations->showEditedCB (); +} + +void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + dcbIterations->setDefault( defParams->raw.bayersensor.dcb_iterations); + lmmseIterations->setDefault( defParams->raw.bayersensor.lmmse_iterations); + ccSteps->setDefault (defParams->raw.bayersensor.ccSteps); + if (pedited) { + dcbIterations->setDefaultEditedState( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited); + lmmseIterations->setDefaultEditedState( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); + ccSteps->setDefaultEditedState(pedited->raw.bayersensor.ccSteps ? Edited : UnEdited); + }else{ + dcbIterations->setDefaultEditedState( Irrelevant ); + lmmseIterations->setDefaultEditedState( Irrelevant ); + ccSteps->setDefaultEditedState(Irrelevant ); + } +} + +void BayerProcess::adjusterChanged (Adjuster* a, double newval) +{ + if (listener) { + if (a == dcbIterations) + listener->panelChanged (EvDemosaicDCBIter, a->getTextValue() ); + else if (a == ccSteps) + listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); + else if (a == lmmseIterations) + listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() ); + } +} + +void BayerProcess::methodChanged () +{ + int curSelection = method->get_active_row_number(); + if ( curSelection == procparams::RAWParams::BayerSensor::dcb){ + dcbOptions->show(); + }else{ + dcbOptions->hide(); + } + if ( curSelection == procparams::RAWParams::BayerSensor::lmmse){ + lmmseOptions->show(); + }else{ + lmmseOptions->hide(); + } + + Glib::ustring methodName=""; + bool ppreq = false; + if( curSelection>=0 && curSelection < procparams::RAWParams::BayerSensor::numMethods) { + methodName = procparams::RAWParams::BayerSensor::methodstring[curSelection]; + if (curSelection == procparams::RAWParams::BayerSensor::mono || oldSelection == procparams::RAWParams::BayerSensor::mono) { + ppreq = true; + } + } + oldSelection = curSelection; + + if (listener) + listener->panelChanged (ppreq ? EvDemosaicMethodPreProc : EvDemosaicMethod, methodName); +} + +void BayerProcess::dcbEnhanceChanged () +{ + if (batchMode) { + if (dcbEnhance->get_inconsistent()) { + dcbEnhance->set_inconsistent (false); + dcbEnhconn.block (true); + dcbEnhance->set_active (false); + dcbEnhconn.block (false); + } + else if (lastDCBen) + dcbEnhance->set_inconsistent (true); + + lastDCBen = dcbEnhance->get_active (); + } + if (listener) + listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); +} + +/*void BayerProcess::allEnhanceChanged () +{ + if (batchMode) { + if (allEnhance->get_inconsistent()) { + allEnhance->set_inconsistent (false); + allEnhconn.block (true); + allEnhance->set_active (false); + allEnhconn.block (false); + } + else if (lastALLen) + allEnhance->set_inconsistent (true); + + lastALLen = allEnhance->get_active (); + } + if (listener) + listener->panelChanged (EvDemosaicALLEnhanced, allEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); +}*/ diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index cb281832b..4eed5bf32 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -1,61 +1,61 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _BAYERPROCESS_H_ -#define _BAYERPROCESS_H_ - -#include -#include "adjuster.h" -#include "guiutils.h" -#include "toolpanel.h" - - -class BayerProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel{ - - protected: - - MyComboBoxText* method; - Adjuster* ccSteps; - Gtk::VBox *dcbOptions; - Adjuster* dcbIterations; - Gtk::CheckButton* dcbEnhance; - //Gtk::VBox *allOptions; - //Gtk::CheckButton* allEnhance; - Gtk::VBox *lmmseOptions; - Adjuster* lmmseIterations; - - bool lastDCBen; - int oldSelection; - //bool lastALLen; - sigc::connection methodconn,dcbEnhconn; //,allEnhconn; - public: - - BayerProcess (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - - void methodChanged (); - void adjusterChanged (Adjuster* a, double newval); - void dcbEnhanceChanged(); - //void allEnhanceChanged(); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _BAYERPROCESS_H_ +#define _BAYERPROCESS_H_ + +#include +#include "adjuster.h" +#include "guiutils.h" +#include "toolpanel.h" + + +class BayerProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel{ + + protected: + + MyComboBoxText* method; + Adjuster* ccSteps; + Gtk::VBox *dcbOptions; + Adjuster* dcbIterations; + Gtk::CheckButton* dcbEnhance; + //Gtk::VBox *allOptions; + //Gtk::CheckButton* allEnhance; + Gtk::VBox *lmmseOptions; + Adjuster* lmmseIterations; + + bool lastDCBen; + int oldSelection; + //bool lastALLen; + sigc::connection methodconn,dcbEnhconn; //,allEnhconn; + public: + + BayerProcess (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + + void methodChanged (); + void adjusterChanged (Adjuster* a, double newval); + void dcbEnhanceChanged(); + //void allEnhanceChanged(); +}; + +#endif diff --git a/rtgui/bayerrawexposure.cc b/rtgui/bayerrawexposure.cc index 402c1063b..f63912f4d 100644 --- a/rtgui/bayerrawexposure.cc +++ b/rtgui/bayerrawexposure.cc @@ -1,185 +1,185 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "bayerrawexposure.h" -#include "guiutils.h" -#include "../rtengine/safegtk.h" -#include - -using namespace rtengine; -using namespace rtengine::procparams; - -BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, "bayerrawexposure", M("TP_EXPOS_BLACKPOINT_LABEL"), true) -{ - PexBlack1 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_1"),-2048,2048,0.1,0));//black level - PexBlack1->setAdjusterListener (this); - if (PexBlack1->delay < 1000) PexBlack1->delay = 1000; - PexBlack1->show(); - PexBlack2 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_2"),-2048,2048,0.1,0));//black level - PexBlack2->setAdjusterListener (this); - if (PexBlack2->delay < 1000) PexBlack2->delay = 1000; - PexBlack2->show(); - PexBlack3 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_3"),-2048,2048,0.1,0));//black level - PexBlack3->setAdjusterListener (this); - if (PexBlack3->delay < 1000) PexBlack3->delay = 1000; - PexBlack3->show(); - PexBlack0 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_0"),-2048,2048,0.1,0));//black level - PexBlack0->setAdjusterListener (this); - if (PexBlack0->delay < 1000) PexBlack0->delay = 1000; - PexBlack0->show(); - PextwoGreen = Gtk::manage(new Gtk::CheckButton((M("TP_RAWEXPOS_TWOGREEN"))));// two green - PextwoGreen->set_active (true); - greenconn = PextwoGreen->signal_toggled().connect ( sigc::mem_fun(*this, &BayerRAWExposure::GreenChanged)); - - pack_start( *PexBlack1, Gtk::PACK_SHRINK, 0);//black R - pack_start( *PexBlack0, Gtk::PACK_SHRINK, 0);//black G1 - pack_start( *PexBlack3, Gtk::PACK_SHRINK, 0);//black G2 - pack_start( *PexBlack2, Gtk::PACK_SHRINK, 0);//black B - pack_start( *PextwoGreen, Gtk::PACK_SHRINK, 0);//black 2 green -} - -void BayerRAWExposure::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - - if(pedited ){ - PexBlack0->setEditedState( pedited->raw.bayersensor.exBlack0 ? Edited : UnEdited ); - PexBlack1->setEditedState( pedited->raw.bayersensor.exBlack1 ? Edited : UnEdited ); - PexBlack2->setEditedState( pedited->raw.bayersensor.exBlack2 ? Edited : UnEdited ); - PexBlack3->setEditedState( pedited->raw.bayersensor.exBlack3 ? Edited : UnEdited ); - } - greenconn.block (true); - PextwoGreen->set_active (pp->raw.bayersensor.twogreen); - greenconn.block (false); - lastPextwoGreen = pp->raw.bayersensor.twogreen; - - PexBlack0->setValue (pp->raw.bayersensor.black0);//black - PexBlack1->setValue (pp->raw.bayersensor.black1);//black - PexBlack2->setValue (pp->raw.bayersensor.black2);//black - - if(!PextwoGreen->get_active())PexBlack3->setValue (pp->raw.bayersensor.black3);else PexBlack3->setValue (PexBlack0->getValue()); - - enableListener (); -} - -void BayerRAWExposure::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.bayersensor.black0 = PexBlack0->getValue();// black - pp->raw.bayersensor.black1 = PexBlack1->getValue();// black - pp->raw.bayersensor.black2 = PexBlack2->getValue();// black - pp->raw.bayersensor.twogreen=PextwoGreen->get_active(); - if(PextwoGreen->get_active()){pp->raw.bayersensor.black3=pp->raw.bayersensor.black0;} else {pp->raw.bayersensor.black3 = PexBlack3->getValue();}// active or desactive 2 green together - - if (pedited) { - pedited->raw.bayersensor.exBlack0 = PexBlack0->getEditedState ();//black - pedited->raw.bayersensor.exBlack1 = PexBlack1->getEditedState ();//black - pedited->raw.bayersensor.exBlack2 = PexBlack2->getEditedState ();//black - pedited->raw.bayersensor.exBlack3 = PexBlack3->getEditedState ();//black - pedited->raw.bayersensor.exTwoGreen =!PextwoGreen->get_inconsistent(); - } - -} - -void BayerRAWExposure::adjusterChanged (Adjuster* a, double newval) -{ - if (listener) { - Glib::ustring value = a->getTextValue(); - if (a == PexBlack0) {if(!PextwoGreen->get_active()) - listener->panelChanged (EvPreProcessExpBlackzero, value ); else {listener->panelChanged (EvPreProcessExpBlackzero, value );PexBlack3->setValue (PexBlack0->getValue());}} - else if (a == PexBlack1) - listener->panelChanged (EvPreProcessExpBlackone, value ); - else if (a == PexBlack2) - listener->panelChanged (EvPreProcessExpBlacktwo, value ); - else if (a == PexBlack3) {if(!PextwoGreen->get_active()) - listener->panelChanged (EvPreProcessExpBlackthree, value ); else {listener->panelChanged (EvPreProcessExpBlackthree, value );PexBlack0->setValue (PexBlack3->getValue());}} - } -} -void BayerRAWExposure::GreenChanged() { - if (batchMode) { - if (PextwoGreen->get_inconsistent()) { - PextwoGreen->set_inconsistent (false); - greenconn.block (true); - PextwoGreen->set_active (false); - greenconn.block (false); - } - else if (lastPextwoGreen) - PextwoGreen->set_inconsistent (true); - lastPextwoGreen = PextwoGreen->get_active (); - } - - if (listener) { - if (PextwoGreen->get_active()) - { listener->panelChanged (EvPreProcessExptwoGreen, M("GENERAL_ENABLED")); - PexBlack3->setValue (PexBlack0->getValue());//two green together - } - - else - { listener->panelChanged (EvPreProcessExptwoGreen, M("GENERAL_DISABLED")); - } - - } - -} - -void BayerRAWExposure::setBatchMode(bool batchMode) -{ - ToolPanel::setBatchMode (batchMode); - PexBlack0->showEditedCB ();//black - PexBlack1->showEditedCB ();//black - PexBlack2->showEditedCB ();//black - PexBlack3->showEditedCB ();//black - -} - -void BayerRAWExposure::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) -{ - PexBlack0->setDefault( defParams->raw.bayersensor.black0); - PexBlack1->setDefault( defParams->raw.bayersensor.black1); - PexBlack2->setDefault( defParams->raw.bayersensor.black2); - PexBlack3->setDefault( defParams->raw.bayersensor.black3); - - if (pedited) { - PexBlack0->setDefaultEditedState( pedited->raw.bayersensor.exBlack0 ? Edited : UnEdited); - PexBlack1->setDefaultEditedState( pedited->raw.bayersensor.exBlack1 ? Edited : UnEdited); - PexBlack2->setDefaultEditedState( pedited->raw.bayersensor.exBlack2 ? Edited : UnEdited); - PexBlack3->setDefaultEditedState( pedited->raw.bayersensor.exBlack3 ? Edited : UnEdited); - - } else { - PexBlack0->setDefaultEditedState( Irrelevant ); - PexBlack1->setDefaultEditedState( Irrelevant ); - PexBlack2->setDefaultEditedState( Irrelevant ); - PexBlack3->setDefaultEditedState( Irrelevant ); - - } -} - -void BayerRAWExposure::setAdjusterBehavior (bool pexblackadd) { - - PexBlack0->setAddMode(pexblackadd); - PexBlack1->setAddMode(pexblackadd); - PexBlack2->setAddMode(pexblackadd); - PexBlack3->setAddMode(pexblackadd); -} - -void BayerRAWExposure::trimValues (rtengine::procparams::ProcParams* pp) { - - PexBlack0->trimValue(pp->raw.bayersensor.black0); - PexBlack1->trimValue(pp->raw.bayersensor.black1); - PexBlack2->trimValue(pp->raw.bayersensor.black2); - PexBlack3->trimValue(pp->raw.bayersensor.black3); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "bayerrawexposure.h" +#include "guiutils.h" +#include "../rtengine/safegtk.h" +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, "bayerrawexposure", M("TP_EXPOS_BLACKPOINT_LABEL"), true) +{ + PexBlack1 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_1"),-2048,2048,0.1,0));//black level + PexBlack1->setAdjusterListener (this); + if (PexBlack1->delay < 1000) PexBlack1->delay = 1000; + PexBlack1->show(); + PexBlack2 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_2"),-2048,2048,0.1,0));//black level + PexBlack2->setAdjusterListener (this); + if (PexBlack2->delay < 1000) PexBlack2->delay = 1000; + PexBlack2->show(); + PexBlack3 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_3"),-2048,2048,0.1,0));//black level + PexBlack3->setAdjusterListener (this); + if (PexBlack3->delay < 1000) PexBlack3->delay = 1000; + PexBlack3->show(); + PexBlack0 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_0"),-2048,2048,0.1,0));//black level + PexBlack0->setAdjusterListener (this); + if (PexBlack0->delay < 1000) PexBlack0->delay = 1000; + PexBlack0->show(); + PextwoGreen = Gtk::manage(new Gtk::CheckButton((M("TP_RAWEXPOS_TWOGREEN"))));// two green + PextwoGreen->set_active (true); + greenconn = PextwoGreen->signal_toggled().connect ( sigc::mem_fun(*this, &BayerRAWExposure::GreenChanged)); + + pack_start( *PexBlack1, Gtk::PACK_SHRINK, 0);//black R + pack_start( *PexBlack0, Gtk::PACK_SHRINK, 0);//black G1 + pack_start( *PexBlack3, Gtk::PACK_SHRINK, 0);//black G2 + pack_start( *PexBlack2, Gtk::PACK_SHRINK, 0);//black B + pack_start( *PextwoGreen, Gtk::PACK_SHRINK, 0);//black 2 green +} + +void BayerRAWExposure::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + + if(pedited ){ + PexBlack0->setEditedState( pedited->raw.bayersensor.exBlack0 ? Edited : UnEdited ); + PexBlack1->setEditedState( pedited->raw.bayersensor.exBlack1 ? Edited : UnEdited ); + PexBlack2->setEditedState( pedited->raw.bayersensor.exBlack2 ? Edited : UnEdited ); + PexBlack3->setEditedState( pedited->raw.bayersensor.exBlack3 ? Edited : UnEdited ); + } + greenconn.block (true); + PextwoGreen->set_active (pp->raw.bayersensor.twogreen); + greenconn.block (false); + lastPextwoGreen = pp->raw.bayersensor.twogreen; + + PexBlack0->setValue (pp->raw.bayersensor.black0);//black + PexBlack1->setValue (pp->raw.bayersensor.black1);//black + PexBlack2->setValue (pp->raw.bayersensor.black2);//black + + if(!PextwoGreen->get_active())PexBlack3->setValue (pp->raw.bayersensor.black3);else PexBlack3->setValue (PexBlack0->getValue()); + + enableListener (); +} + +void BayerRAWExposure::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.bayersensor.black0 = PexBlack0->getValue();// black + pp->raw.bayersensor.black1 = PexBlack1->getValue();// black + pp->raw.bayersensor.black2 = PexBlack2->getValue();// black + pp->raw.bayersensor.twogreen=PextwoGreen->get_active(); + if(PextwoGreen->get_active()){pp->raw.bayersensor.black3=pp->raw.bayersensor.black0;} else {pp->raw.bayersensor.black3 = PexBlack3->getValue();}// active or desactive 2 green together + + if (pedited) { + pedited->raw.bayersensor.exBlack0 = PexBlack0->getEditedState ();//black + pedited->raw.bayersensor.exBlack1 = PexBlack1->getEditedState ();//black + pedited->raw.bayersensor.exBlack2 = PexBlack2->getEditedState ();//black + pedited->raw.bayersensor.exBlack3 = PexBlack3->getEditedState ();//black + pedited->raw.bayersensor.exTwoGreen =!PextwoGreen->get_inconsistent(); + } + +} + +void BayerRAWExposure::adjusterChanged (Adjuster* a, double newval) +{ + if (listener) { + Glib::ustring value = a->getTextValue(); + if (a == PexBlack0) {if(!PextwoGreen->get_active()) + listener->panelChanged (EvPreProcessExpBlackzero, value ); else {listener->panelChanged (EvPreProcessExpBlackzero, value );PexBlack3->setValue (PexBlack0->getValue());}} + else if (a == PexBlack1) + listener->panelChanged (EvPreProcessExpBlackone, value ); + else if (a == PexBlack2) + listener->panelChanged (EvPreProcessExpBlacktwo, value ); + else if (a == PexBlack3) {if(!PextwoGreen->get_active()) + listener->panelChanged (EvPreProcessExpBlackthree, value ); else {listener->panelChanged (EvPreProcessExpBlackthree, value );PexBlack0->setValue (PexBlack3->getValue());}} + } +} +void BayerRAWExposure::GreenChanged() { + if (batchMode) { + if (PextwoGreen->get_inconsistent()) { + PextwoGreen->set_inconsistent (false); + greenconn.block (true); + PextwoGreen->set_active (false); + greenconn.block (false); + } + else if (lastPextwoGreen) + PextwoGreen->set_inconsistent (true); + lastPextwoGreen = PextwoGreen->get_active (); + } + + if (listener) { + if (PextwoGreen->get_active()) + { listener->panelChanged (EvPreProcessExptwoGreen, M("GENERAL_ENABLED")); + PexBlack3->setValue (PexBlack0->getValue());//two green together + } + + else + { listener->panelChanged (EvPreProcessExptwoGreen, M("GENERAL_DISABLED")); + } + + } + +} + +void BayerRAWExposure::setBatchMode(bool batchMode) +{ + ToolPanel::setBatchMode (batchMode); + PexBlack0->showEditedCB ();//black + PexBlack1->showEditedCB ();//black + PexBlack2->showEditedCB ();//black + PexBlack3->showEditedCB ();//black + +} + +void BayerRAWExposure::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + PexBlack0->setDefault( defParams->raw.bayersensor.black0); + PexBlack1->setDefault( defParams->raw.bayersensor.black1); + PexBlack2->setDefault( defParams->raw.bayersensor.black2); + PexBlack3->setDefault( defParams->raw.bayersensor.black3); + + if (pedited) { + PexBlack0->setDefaultEditedState( pedited->raw.bayersensor.exBlack0 ? Edited : UnEdited); + PexBlack1->setDefaultEditedState( pedited->raw.bayersensor.exBlack1 ? Edited : UnEdited); + PexBlack2->setDefaultEditedState( pedited->raw.bayersensor.exBlack2 ? Edited : UnEdited); + PexBlack3->setDefaultEditedState( pedited->raw.bayersensor.exBlack3 ? Edited : UnEdited); + + } else { + PexBlack0->setDefaultEditedState( Irrelevant ); + PexBlack1->setDefaultEditedState( Irrelevant ); + PexBlack2->setDefaultEditedState( Irrelevant ); + PexBlack3->setDefaultEditedState( Irrelevant ); + + } +} + +void BayerRAWExposure::setAdjusterBehavior (bool pexblackadd) { + + PexBlack0->setAddMode(pexblackadd); + PexBlack1->setAddMode(pexblackadd); + PexBlack2->setAddMode(pexblackadd); + PexBlack3->setAddMode(pexblackadd); +} + +void BayerRAWExposure::trimValues (rtengine::procparams::ProcParams* pp) { + + PexBlack0->trimValue(pp->raw.bayersensor.black0); + PexBlack1->trimValue(pp->raw.bayersensor.black1); + PexBlack2->trimValue(pp->raw.bayersensor.black2); + PexBlack3->trimValue(pp->raw.bayersensor.black3); +} diff --git a/rtgui/bayerrawexposure.h b/rtgui/bayerrawexposure.h index e485fb12b..bb8f9eb20 100644 --- a/rtgui/bayerrawexposure.h +++ b/rtgui/bayerrawexposure.h @@ -1,54 +1,54 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _BAYERRAWEXPOSURE_H_ -#define _BAYERRAWEXPOSURE_H_ - -#include -#include "adjuster.h" -#include "toolpanel.h" -#include "../rtengine/rawimage.h" - -class BayerRAWExposure : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { - -protected: - Adjuster* PexBlack0; - Adjuster* PexBlack1; - Adjuster* PexBlack2; - Adjuster* PexBlack3; - bool lastPextwoGreen; - sigc::connection greenconn; - Gtk::CheckButton* PextwoGreen; - -private: -// Gtk::CheckButton* PextwoGreen; -public: - - BayerRAWExposure (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - void GreenChanged() ; - void adjusterChanged (Adjuster* a, double newval); - void setAdjusterBehavior (bool pexblackadd); - void trimValues (rtengine::procparams::ProcParams* pp); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _BAYERRAWEXPOSURE_H_ +#define _BAYERRAWEXPOSURE_H_ + +#include +#include "adjuster.h" +#include "toolpanel.h" +#include "../rtengine/rawimage.h" + +class BayerRAWExposure : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { + +protected: + Adjuster* PexBlack0; + Adjuster* PexBlack1; + Adjuster* PexBlack2; + Adjuster* PexBlack3; + bool lastPextwoGreen; + sigc::connection greenconn; + Gtk::CheckButton* PextwoGreen; + +private: +// Gtk::CheckButton* PextwoGreen; +public: + + BayerRAWExposure (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void GreenChanged() ; + void adjusterChanged (Adjuster* a, double newval); + void setAdjusterBehavior (bool pexblackadd); + void trimValues (rtengine::procparams::ProcParams* pp); +}; + +#endif diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc index 6112585ec..801c9981e 100644 --- a/rtgui/cachemanager.cc +++ b/rtgui/cachemanager.cc @@ -290,9 +290,9 @@ std::string CacheManager::getMD5 (const Glib::ustring& fname) { Glib::RefPtr file = Gio::File::create_for_path (fname); if (file && file->query_exists()) { - #ifdef WIN32 - // Windows: file name + size + creation time - // Safer because e.g. your camera image counter turns over. Do NOT use modified date, since tagging programs will change that + #ifdef WIN32 + // Windows: file name + size + creation time + // Safer because e.g. your camera image counter turns over. Do NOT use modified date, since tagging programs will change that wchar_t *wFname = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); WIN32_FILE_ATTRIBUTE_DATA fileAttr; bool success=GetFileAttributesExW(wFname, GetFileExInfoStandard, &fileAttr); diff --git a/rtgui/coloredbar.cc b/rtgui/coloredbar.cc index de41b8312..f13e801c9 100644 --- a/rtgui/coloredbar.cc +++ b/rtgui/coloredbar.cc @@ -1,177 +1,177 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include "coloredbar.h" - -ColoredBar::ColoredBar (eRTOrientation orient) { - orientation = orient; - dirty = true; - this->x = this->y = this->w = this->h = 0; -} - -/* - * Redraw the bar to a Cairo::ImageSurface - */ -void ColoredBar::expose(Cairo::RefPtr destSurface) { - // look out if the Surface has to be redrawn - if (!surfaceCreated() || !destSurface) - return; - draw(); - copySurface(destSurface); -} - -/* - * Redraw the bar to a Gdk::Window - */ -void ColoredBar::expose(Glib::RefPtr destWindow) { - // look out if the Surface has to be redrawn - if (!surfaceCreated() || !destWindow) - return; - draw(); - copySurface(destWindow); -} - -/* - * Redraw the bar to a Gdk::Window - */ -void ColoredBar::expose(BackBuffer *backBuffer) { - // look out if the Surface has to be redrawn - if (!surfaceCreated() || !backBuffer) - return; - draw(); - copySurface(backBuffer); -} - -void ColoredBar::draw() { - if (isDirty()) { - Cairo::RefPtr cr = getContext(); - // the bar has to be drawn to the Surface first - if (!bgGradient.empty()) { - // a gradient has been set, we use it - cr->set_line_width(0.); - - // gradient background - Cairo::RefPtr< Cairo::LinearGradient > bggradient; - switch (orientation) { - case (RTO_Left2Right): - bggradient = Cairo::LinearGradient::create (0., 0., double(w), 0.); - break; - case (RTO_Right2Left): - bggradient = Cairo::LinearGradient::create (double(w), 0., 0., 0.); - break; - case (RTO_Bottom2Top): - bggradient = Cairo::LinearGradient::create (0., double(h), 0., 0.); - break; - case (RTO_Top2Bottom): - default: - bggradient = Cairo::LinearGradient::create (0., 0., 0., double(h)); - break; - } - - for (std::vector::iterator i=bgGradient.begin(); i!=bgGradient.end(); i++) { - bggradient->add_color_stop_rgb (i->position, i->r, i->g, i->b); - } - cr->set_source (bggradient); - cr->rectangle(0, 0, w, h); - cr->fill(); - } - else { - // ask the ColorProvider to provide colors :) for each pixels - if (colorProvider) { - cr->set_antialias(Cairo::ANTIALIAS_NONE); - cr->set_line_width(1.); - switch (orientation) { - case (RTO_Left2Right): - for (int x=0; xcolorForValue (x01, y01, CCET_BACKGROUND, colorCallerId, this); - cr->set_source_rgb(ccRed, ccGreen, ccBlue); - cr->rectangle(x_, y_, 1., 1.); - cr->fill(); - } - } - break; - case (RTO_Right2Left): - for (int x=0; xcolorForValue (x01, y01, CCET_BACKGROUND, colorCallerId, this); - cr->set_source_rgb(ccRed, ccGreen, ccBlue); - cr->rectangle(x_, y_, 1., 1.); - cr->fill(); - } - } - break; - case (RTO_Bottom2Top): - for (int x=0; xcolorForValue (y01, x01, CCET_BACKGROUND, colorCallerId, this); - cr->set_source_rgb(ccRed, ccGreen, ccBlue); - cr->rectangle(x_, y_, 1., 1.); - cr->fill(); - } - } - break; - case (RTO_Top2Bottom): - default: - for (int x=0; xcolorForValue (y01, x01, CCET_BACKGROUND, colorCallerId, this); - cr->set_source_rgb(ccRed, ccGreen, ccBlue); - cr->rectangle(x_, y_, 1., 1.); - cr->fill(); - } - } - break; - } - } - } - // has it been updated or not, we assume that the Surface has been correctly set (we don't handle allocation error) - setDirty(false); - } -} - -void ColoredBar::setBgGradient (const std::vector &milestones) { - bgGradient = milestones; - setDirty(true); -} - -void ColoredBar::clearBgGradient () { - bgGradient.clear(); - setDirty(true); -} - -bool ColoredBar::canGetColors() { - return colorProvider!=NULL || bgGradient.size()>0; -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "coloredbar.h" + +ColoredBar::ColoredBar (eRTOrientation orient) { + orientation = orient; + dirty = true; + this->x = this->y = this->w = this->h = 0; +} + +/* + * Redraw the bar to a Cairo::ImageSurface + */ +void ColoredBar::expose(Cairo::RefPtr destSurface) { + // look out if the Surface has to be redrawn + if (!surfaceCreated() || !destSurface) + return; + draw(); + copySurface(destSurface); +} + +/* + * Redraw the bar to a Gdk::Window + */ +void ColoredBar::expose(Glib::RefPtr destWindow) { + // look out if the Surface has to be redrawn + if (!surfaceCreated() || !destWindow) + return; + draw(); + copySurface(destWindow); +} + +/* + * Redraw the bar to a Gdk::Window + */ +void ColoredBar::expose(BackBuffer *backBuffer) { + // look out if the Surface has to be redrawn + if (!surfaceCreated() || !backBuffer) + return; + draw(); + copySurface(backBuffer); +} + +void ColoredBar::draw() { + if (isDirty()) { + Cairo::RefPtr cr = getContext(); + // the bar has to be drawn to the Surface first + if (!bgGradient.empty()) { + // a gradient has been set, we use it + cr->set_line_width(0.); + + // gradient background + Cairo::RefPtr< Cairo::LinearGradient > bggradient; + switch (orientation) { + case (RTO_Left2Right): + bggradient = Cairo::LinearGradient::create (0., 0., double(w), 0.); + break; + case (RTO_Right2Left): + bggradient = Cairo::LinearGradient::create (double(w), 0., 0., 0.); + break; + case (RTO_Bottom2Top): + bggradient = Cairo::LinearGradient::create (0., double(h), 0., 0.); + break; + case (RTO_Top2Bottom): + default: + bggradient = Cairo::LinearGradient::create (0., 0., 0., double(h)); + break; + } + + for (std::vector::iterator i=bgGradient.begin(); i!=bgGradient.end(); i++) { + bggradient->add_color_stop_rgb (i->position, i->r, i->g, i->b); + } + cr->set_source (bggradient); + cr->rectangle(0, 0, w, h); + cr->fill(); + } + else { + // ask the ColorProvider to provide colors :) for each pixels + if (colorProvider) { + cr->set_antialias(Cairo::ANTIALIAS_NONE); + cr->set_line_width(1.); + switch (orientation) { + case (RTO_Left2Right): + for (int x=0; xcolorForValue (x01, y01, CCET_BACKGROUND, colorCallerId, this); + cr->set_source_rgb(ccRed, ccGreen, ccBlue); + cr->rectangle(x_, y_, 1., 1.); + cr->fill(); + } + } + break; + case (RTO_Right2Left): + for (int x=0; xcolorForValue (x01, y01, CCET_BACKGROUND, colorCallerId, this); + cr->set_source_rgb(ccRed, ccGreen, ccBlue); + cr->rectangle(x_, y_, 1., 1.); + cr->fill(); + } + } + break; + case (RTO_Bottom2Top): + for (int x=0; xcolorForValue (y01, x01, CCET_BACKGROUND, colorCallerId, this); + cr->set_source_rgb(ccRed, ccGreen, ccBlue); + cr->rectangle(x_, y_, 1., 1.); + cr->fill(); + } + } + break; + case (RTO_Top2Bottom): + default: + for (int x=0; xcolorForValue (y01, x01, CCET_BACKGROUND, colorCallerId, this); + cr->set_source_rgb(ccRed, ccGreen, ccBlue); + cr->rectangle(x_, y_, 1., 1.); + cr->fill(); + } + } + break; + } + } + } + // has it been updated or not, we assume that the Surface has been correctly set (we don't handle allocation error) + setDirty(false); + } +} + +void ColoredBar::setBgGradient (const std::vector &milestones) { + bgGradient = milestones; + setDirty(true); +} + +void ColoredBar::clearBgGradient () { + bgGradient.clear(); + setDirty(true); +} + +bool ColoredBar::canGetColors() { + return colorProvider!=NULL || bgGradient.size()>0; +} diff --git a/rtgui/coloredbar.h b/rtgui/coloredbar.h index 8e62e20ed..d0351b6a5 100644 --- a/rtgui/coloredbar.h +++ b/rtgui/coloredbar.h @@ -1,54 +1,54 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _COLOREDBAR_ -#define _COLOREDBAR_ - -#include "colorprovider.h" -#include "guiutils.h" - -/* - * Parent class for all colored bar type; a ColorProvider has to be set - * thanks to "setColorProvider" to be able to display colors inside the bar - */ -class ColoredBar : public BackBuffer, public ColorCaller { - - private: - void draw(); - - protected: - eRTOrientation orientation; - std::vector bgGradient; - - public: - ColoredBar (eRTOrientation orient); - - void expose(Glib::RefPtr destWindow); - void expose(Cairo::RefPtr destSurface); - void expose(BackBuffer *backBuffer); - - bool canGetColors(); - - // Method for convenience; if no Gradient provided, the ColoredBar will ask colors on a per pixel basis - void setBgGradient (const std::vector &milestones); - // by clearing the gradient, the ColorProvider will have to provide colors on a per pixel basis if a ColorProvider - // has been set, through ColorProvider::colorForValue on next ColoredBar::expose - void clearBgGradient (); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _COLOREDBAR_ +#define _COLOREDBAR_ + +#include "colorprovider.h" +#include "guiutils.h" + +/* + * Parent class for all colored bar type; a ColorProvider has to be set + * thanks to "setColorProvider" to be able to display colors inside the bar + */ +class ColoredBar : public BackBuffer, public ColorCaller { + + private: + void draw(); + + protected: + eRTOrientation orientation; + std::vector bgGradient; + + public: + ColoredBar (eRTOrientation orient); + + void expose(Glib::RefPtr destWindow); + void expose(Cairo::RefPtr destSurface); + void expose(BackBuffer *backBuffer); + + bool canGetColors(); + + // Method for convenience; if no Gradient provided, the ColoredBar will ask colors on a per pixel basis + void setBgGradient (const std::vector &milestones); + // by clearing the gradient, the ColorProvider will have to provide colors on a per pixel basis if a ColorProvider + // has been set, through ColorProvider::colorForValue on next ColoredBar::expose + void clearBgGradient (); +}; + +#endif diff --git a/rtgui/colorprovider.h b/rtgui/colorprovider.h index f2ad08205..94383f882 100644 --- a/rtgui/colorprovider.h +++ b/rtgui/colorprovider.h @@ -1,64 +1,64 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _COLORPROVIDER_ -#define _COLORPROVIDER_ - -#include - -class ColorProvider; - -/* - * The ColorCaller is the class that will query the ColorProvider - */ -class ColorCaller { - protected: - // a class can handle several ColorCaller; - // colorCallerId will let the provider identify the caller - int colorCallerId; - ColorProvider* colorProvider; - - public: - enum ElemType { - CCET_POINT, - CCET_VERTICAL_BAR, - CCET_HORIZONTAL_BAR, - CCET_BACKGROUND - }; - double ccRed; - double ccGreen; - double ccBlue; - - ColorCaller() : colorCallerId(-1), colorProvider(NULL), ccRed(0.), ccGreen(0.), ccBlue(0.) {} - void setColorProvider (ColorProvider* p, int id) { colorProvider = p; colorCallerId = id; } -}; - -/* - * Use it to let your widget feed a colored bar or graph lines with the wanted colors - * If you doesn't need to dynamically feed a widget with colors (e.g. curve's graph), - * you don't need to declare the instanciator class as BEING a ColorProvider, you'll - * still be able to set gradients for e.g. ColoredBar(s) - */ -class ColorProvider { - - public: - virtual ~ColorProvider() {}; - virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller) {}; -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _COLORPROVIDER_ +#define _COLORPROVIDER_ + +#include + +class ColorProvider; + +/* + * The ColorCaller is the class that will query the ColorProvider + */ +class ColorCaller { + protected: + // a class can handle several ColorCaller; + // colorCallerId will let the provider identify the caller + int colorCallerId; + ColorProvider* colorProvider; + + public: + enum ElemType { + CCET_POINT, + CCET_VERTICAL_BAR, + CCET_HORIZONTAL_BAR, + CCET_BACKGROUND + }; + double ccRed; + double ccGreen; + double ccBlue; + + ColorCaller() : colorCallerId(-1), colorProvider(NULL), ccRed(0.), ccGreen(0.), ccBlue(0.) {} + void setColorProvider (ColorProvider* p, int id) { colorProvider = p; colorCallerId = id; } +}; + +/* + * Use it to let your widget feed a colored bar or graph lines with the wanted colors + * If you doesn't need to dynamically feed a widget with colors (e.g. curve's graph), + * you don't need to declare the instanciator class as BEING a ColorProvider, you'll + * still be able to set gradients for e.g. ColoredBar(s) + */ +class ColorProvider { + + public: + virtual ~ColorProvider() {}; + virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller) {}; +}; + +#endif diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc index 32d232870..3abbffc66 100644 --- a/rtgui/colortoning.cc +++ b/rtgui/colortoning.cc @@ -1,1090 +1,1090 @@ -/* - * This file is part of RawTherapee. - */ -#include "colortoning.h" -#include "mycurve.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -ColorToning::ColorToning () : FoldableToolPanel(this, "colortoning", M("TP_COLORTONING_LABEL"), false, true) -{ - nextbw=0; - CurveListener::setMulti(true); - - //---------------method - - method = Gtk::manage (new MyComboBoxText ()); - method->append_text (M("TP_COLORTONING_LAB")); - method->append_text (M("TP_COLORTONING_RGBSLIDERS")); - method->append_text (M("TP_COLORTONING_RGBCURVES")); - method->append_text (M("TP_COLORTONING_SPLITCOCO")); - method->append_text (M("TP_COLORTONING_SPLITLR")); - method->set_active (0); - method->set_tooltip_text (M("TP_COLORTONING_METHOD_TOOLTIP")); - - ctbox = Gtk::manage (new Gtk::HBox ()); - Gtk::Label* lab = Gtk::manage (new Gtk::Label (M("TP_COLORTONING_METHOD"))); - ctbox->pack_start (*lab, Gtk::PACK_SHRINK, 4); - ctbox->pack_start (*method); - pack_start (*ctbox); - - methodconn = method->signal_changed().connect ( sigc::mem_fun(*this, &ColorToning::methodChanged) ); - - //----------- Color curve ------------------------------ - - colorSep = Gtk::manage (new Gtk::HSeparator()); - pack_start (*colorSep); - - colLabel = Gtk::manage (new Gtk::Label (M("TP_COLORTONING_LABCOL"))); - colLabel->set_tooltip_text (M("TP_COLORTONING_LABCOL_TOOLTIP")); - - interLabel = Gtk::manage (new Gtk::Label (M("TP_COLORTONING_LABINT"))); - interLabel->set_tooltip_text (M("TP_COLORTONING_LABINT_TOOLTIP")); - pack_start (*colLabel, Gtk::PACK_SHRINK, 4); - pack_start (*interLabel, Gtk::PACK_SHRINK, 4); - - colorCurveEditorG = new CurveEditorGroup (options.lastColorToningCurvesDir, M("TP_COLORTONING_COLOR")); - colorCurveEditorG->setCurveListener (this); - - colorShape = static_cast(colorCurveEditorG->addCurve(CT_Flat, "", NULL, false)); - colorShape->setCurveColorProvider(this, 1); - std::vector milestones; - // whole hue range - for (int i=0; i<7; i++) { - float R, G, B; - float x = float(i)*(1.0f/6.0); - Color::hsv2rgb01(x, 0.5f, 0.5f, R, G, B); - milestones.push_back( GradientMilestone(double(x), double(R), double(G), double(B)) ); - } - colorShape->setLeftBarBgGradient(milestones); - - // luminance gradient - milestones.clear(); - milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); - milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); - colorShape->setBottomBarBgGradient(milestones); - std::vector defaultCurve; - rtengine::ColorToningParams::getDefaultColorCurve(defaultCurve); - colorShape->setResetCurve(FCT_MinMaxCPoints, defaultCurve); - - // This will add the reset button at the end of the curveType buttons - colorCurveEditorG->curveListComplete(); - colorCurveEditorG->show(); - - pack_start( *colorCurveEditorG, Gtk::PACK_SHRINK, 2); - - //----------------------red green blue yellow colours - - twocolor = Gtk::manage (new MyComboBoxText ()); - twocolor->append_text (M("TP_COLORTONING_TWOSTD")); - twocolor->append_text (M("TP_COLORTONING_TWOALL")); - twocolor->append_text (M("TP_COLORTONING_TWOBY")); - twocolor->append_text (M("TP_COLORTONING_TWO2")); - twocolor->set_tooltip_text (M("TP_COLORTONING_TWOCOLOR_TOOLTIP")); - twocolor->set_active (0); - - twocconn = twocolor->signal_changed().connect( sigc::mem_fun(*this, &ColorToning::twoColorChangedByGui) ); - - pack_start (*twocolor, Gtk::PACK_SHRINK, 4); - - //----------- Opacity curve ------------------------------ - - opacityCurveEditorG = new CurveEditorGroup (options.lastColorToningCurvesDir, M("TP_COLORTONING_OPACITY")); - opacityCurveEditorG->setCurveListener (this); - - rtengine::ColorToningParams::getDefaultOpacityCurve(defaultCurve); - opacityShape = static_cast(opacityCurveEditorG->addCurve(CT_Flat, "", NULL, false)); - opacityShape->setIdentityValue(0.); - opacityShape->setResetCurve(FlatCurveType(defaultCurve.at(0)), defaultCurve); - opacityShape->setBottomBarBgGradient(milestones); - - // This will add the reset button at the end of the curveType buttons - opacityCurveEditorG->curveListComplete(); - opacityCurveEditorG->show(); - - pack_start( *opacityCurveEditorG, Gtk::PACK_SHRINK, 2); - - //---------Chroma curve 1 -------------------- - iby = Gtk::manage (new RTImage ("Chanmixer-BY.png")); - irg = Gtk::manage (new RTImage ("Chanmixer-RG.png")); - - clCurveEditorG = new CurveEditorGroup (options.lastColorToningCurvesDir, M("TP_COLORTONING_CHROMAC")); - clCurveEditorG->setCurveListener (this); - - rtengine::ColorToningParams::getDefaultCLCurve(defaultCurve); - clshape = static_cast(clCurveEditorG->addCurve(CT_Diagonal, M("TP_COLORTONING_AB"),irg)); - clshape->setResetCurve(DiagonalCurveType(defaultCurve.at(0)), defaultCurve); - clshape->setTooltip(M("TP_COLORTONING_CURVEEDITOR_CL_TOOLTIP")); - - clshape->setLeftBarColorProvider(this, 1); - clshape->setRangeDefaultMilestones(0.25, 0.5, 0.75); - milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); - milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); - - clshape->setBottomBarBgGradient(milestones); - clCurveEditorG->curveListComplete(); - - pack_start( *clCurveEditorG, Gtk::PACK_SHRINK, 2); - - //---------Chroma curve 2 -------------------- - - cl2CurveEditorG = new CurveEditorGroup (options.lastColorToningCurvesDir, M("TP_COLORTONING_CHROMAC")); - cl2CurveEditorG->setCurveListener (this); - - rtengine::ColorToningParams::getDefaultCL2Curve(defaultCurve); - cl2shape = static_cast(cl2CurveEditorG->addCurve(CT_Diagonal, M("TP_COLORTONING_BY"),iby)); - cl2shape->setResetCurve(DiagonalCurveType(defaultCurve.at(0)), defaultCurve); - cl2shape->setTooltip(M("TP_COLORTONING_CURVEEDITOR_CL_TOOLTIP")); - - cl2shape->setLeftBarColorProvider(this, 1); - cl2shape->setRangeDefaultMilestones(0.25, 0.5, 0.75); - milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); - milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); - - cl2shape->setBottomBarBgGradient(milestones); - cl2CurveEditorG->curveListComplete(); - - pack_start( *cl2CurveEditorG, Gtk::PACK_SHRINK, 2); - - //--------------------- Reset curves ----------------------------- - /* Each curve can reset to a different curve, so this button only save one click now... so we remove it. - neutralCurves = Gtk::manage (new Gtk::Button (M("TP_COLORTONING_NEUTRALCUR"))); - RTImage *resetImgc = Gtk::manage (new RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.png")); - neutralCurves->set_image(*resetImgc); - neutralCurves->set_tooltip_text (M("TP_COLORTONING_NEUTRALCUR_TIP")); - neutralcurvesconn = neutralCurves->signal_pressed().connect( sigc::mem_fun(*this, &ColorToning::neutralCurves_pressed) ); - neutralCurves->show(); - - pack_start (*neutralCurves); - */ - - //----------- Sliders + balance ------------------------------ - - hlColSat = Gtk::manage (new ThresholdAdjuster (M("TP_COLORTONING_HIGHLIGHT"), 0., 100., 60., M("TP_COLORTONING_STRENGTH"), 1., 0., 360., 80., M("TP_COLORTONING_HUE"), 1., NULL, false)); - hlColSat->setAdjusterListener (this); - hlColSat->setBgColorProvider(this, 2); - hlColSat->setUpdatePolicy(RTUP_DYNAMIC); - - pack_start( *hlColSat, Gtk::PACK_SHRINK, 0); - - shadowsColSat = Gtk::manage (new ThresholdAdjuster (M("TP_COLORTONING_SHADOWS"), 0., 100., 80., M("TP_COLORTONING_STRENGTH"), 1., 0., 360., 208., M("TP_COLORTONING_HUE"), 1., NULL, false)); - shadowsColSat->setAdjusterListener (this); - shadowsColSat->setBgColorProvider(this, 3); - shadowsColSat->setUpdatePolicy(RTUP_DYNAMIC); - - pack_start( *shadowsColSat, Gtk::PACK_SHRINK, 0); - - - balance = Gtk::manage( new Adjuster(M("TP_COLORTONING_BALANCE"), -100., 100., 1., 0.) ); - balance->setAdjusterListener(this); - - pack_start (*balance, Gtk::PACK_SHRINK, 2); - - //----------- Saturation and strength ------------------------------ - -// satLimiterSep = Gtk::manage (new Gtk::HSeparator()); - - -// pack_start (*satLimiterSep, Gtk::PACK_SHRINK); - -// Gtk::Frame *p1Frame; - // Vertical box container for the content of the Process 1 frame - Gtk::VBox *p1VBox; - p1Frame = Gtk::manage (new Gtk::Frame(M("TP_COLORTONING_SA")) ); - p1Frame->set_border_width(0); - p1Frame->set_label_align(0.025, 0.5); - - p1VBox = Gtk::manage ( new Gtk::VBox()); - p1VBox->set_border_width(4); - p1VBox->set_spacing(2); - - autosat = Gtk::manage (new Gtk::CheckButton (M("TP_COLORTONING_AUTOSAT"))); - autosat->set_active (true); - autosatConn = autosat->signal_toggled().connect( sigc::mem_fun(*this, &ColorToning::autosatChanged) ); - //satFrame->set_label_widget(*autosat); - - p1VBox->pack_start (*autosat, Gtk::PACK_SHRINK, 2); - - satProtectionThreshold = Gtk::manage( new Adjuster(M("TP_COLORTONING_SATURATIONTHRESHOLD"), 0., 100., 1., 80.) ); - satProtectionThreshold->setAdjusterListener(this); - satProtectionThreshold->set_sensitive(false); - - p1VBox->pack_start( *satProtectionThreshold, Gtk::PACK_SHRINK, 2); - - saturatedOpacity = Gtk::manage( new Adjuster(M("TP_COLORTONING_SATURATEDOPACITY"), 0., 100., 1., 30.) );; - saturatedOpacity->setAdjusterListener(this); - saturatedOpacity->set_sensitive(false); - - p1VBox->pack_start( *saturatedOpacity, Gtk::PACK_SHRINK, 2); //I have moved after Chanmixer - p1Frame->add(*p1VBox); - pack_start (*p1Frame, Gtk::PACK_EXPAND_WIDGET, 4); - - strength = Gtk::manage( new Adjuster(M("TP_COLORTONING_STR"), 0., 100., 1., 50.) );; - strength->setAdjusterListener(this); - - - - // --------------------Sliders BW Colortoning ------------------- - - chanMixerBox = Gtk::manage (new Gtk::VBox()); - Gtk::VBox *chanMixerHLBox = Gtk::manage (new Gtk::VBox()); - Gtk::VBox *chanMixerMidBox = Gtk::manage (new Gtk::VBox()); - Gtk::VBox *chanMixerShadowsBox = Gtk::manage (new Gtk::VBox()); - - Gtk::Image* iblueR = Gtk::manage (new RTImage ("ajd-wb-temp1.png")); - Gtk::Image* iyelL = Gtk::manage (new RTImage ("ajd-wb-temp2.png")); - Gtk::Image* imagL = Gtk::manage (new RTImage ("ajd-wb-green1.png")); - Gtk::Image* igreenR = Gtk::manage (new RTImage ("ajd-wb-green2.png")); - Gtk::Image* icyanL = Gtk::manage (new RTImage ("ajd-wb-bluered1.png")); - Gtk::Image* iredR = Gtk::manage (new RTImage ("ajd-wb-bluered2.png")); - - Gtk::Image* iblueRm = Gtk::manage (new RTImage ("ajd-wb-temp1.png")); - Gtk::Image* iyelLm = Gtk::manage (new RTImage ("ajd-wb-temp2.png")); - Gtk::Image* imagLm = Gtk::manage (new RTImage ("ajd-wb-green1.png")); - Gtk::Image* igreenRm = Gtk::manage (new RTImage ("ajd-wb-green2.png")); - Gtk::Image* icyanLm = Gtk::manage (new RTImage ("ajd-wb-bluered1.png")); - Gtk::Image* iredRm = Gtk::manage (new RTImage ("ajd-wb-bluered2.png")); - - Gtk::Image* iblueRh = Gtk::manage (new RTImage ("ajd-wb-temp1.png")); - Gtk::Image* iyelLh = Gtk::manage (new RTImage ("ajd-wb-temp2.png")); - Gtk::Image* imagLh = Gtk::manage (new RTImage ("ajd-wb-green1.png")); - Gtk::Image* igreenRh = Gtk::manage (new RTImage ("ajd-wb-green2.png")); - Gtk::Image* icyanLh = Gtk::manage (new RTImage ("ajd-wb-bluered1.png")); - Gtk::Image* iredRh = Gtk::manage (new RTImage ("ajd-wb-bluered2.png")); - - redhigh = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., icyanLh, iredRh )); - greenhigh = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., imagLh , igreenRh)); - bluehigh = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., iyelLh , iblueRh )); - - redmed = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., icyanLm, iredRm )); - greenmed = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., imagLm , igreenRm)); - bluemed = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., iyelLm , iblueRm )); - - redlow = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., icyanL, iredR )); - greenlow = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., imagL , igreenR)); - bluelow = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., iyelL , iblueR )); - - chanMixerHLBox->pack_start (*redhigh); - chanMixerHLBox->pack_start (*greenhigh); - chanMixerHLBox->pack_start (*bluehigh); - chanMixerMidBox->pack_start (*redmed); - chanMixerMidBox->pack_start (*greenmed); - chanMixerMidBox->pack_start (*bluemed); - chanMixerShadowsBox->pack_start (*redlow); - chanMixerShadowsBox->pack_start (*greenlow); - chanMixerShadowsBox->pack_start (*bluelow); - - Gtk::Frame *chanMixerHLFrame = Gtk::manage (new Gtk::Frame(M("TP_COLORTONING_HIGHLIGHT"))); - Gtk::Frame *chanMixerMidFrame = Gtk::manage (new Gtk::Frame(M("TP_COLORTONING_MIDTONES"))); - Gtk::Frame *chanMixerShadowsFrame = Gtk::manage (new Gtk::Frame(M("TP_COLORTONING_SHADOWS"))); - - chanMixerHLFrame->add(*chanMixerHLBox); - chanMixerMidFrame->add(*chanMixerMidBox); - chanMixerShadowsFrame->add(*chanMixerShadowsBox); - - chanMixerBox->pack_start(*chanMixerHLFrame, Gtk::PACK_SHRINK); - chanMixerBox->pack_start(*chanMixerMidFrame, Gtk::PACK_SHRINK); - chanMixerBox->pack_start(*chanMixerShadowsFrame, Gtk::PACK_SHRINK); - - pack_start(*chanMixerBox, Gtk::PACK_SHRINK); - pack_start( *strength, Gtk::PACK_SHRINK, 2); //I have moved after Chanmixer - - //--------------------- Reset sliders --------------------------- - neutrHBox = Gtk::manage (new Gtk::HBox ()); - neutrHBox->set_border_width (2); - - neutral = Gtk::manage (new Gtk::Button (M("TP_COLORTONING_NEUTRAL"))); - RTImage *resetImg = Gtk::manage (new RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.png")); - neutral->set_image(*resetImg); - neutral->set_tooltip_text (M("TP_COLORTONING_NEUTRAL_TIP")); - neutralconn = neutral->signal_pressed().connect( sigc::mem_fun(*this, &ColorToning::neutral_pressed) ); - neutral->show(); - neutrHBox->pack_start (*neutral); - - pack_start (*neutrHBox); - - //--------------------- Keep luminance checkbox ------------------- - lumamode = Gtk::manage (new Gtk::CheckButton (M("TP_COLORTONING_LUMAMODE"))); - lumamode->set_tooltip_markup (M("TP_COLORTONING_LUMAMODE_TOOLTIP")); - lumamode->set_active (false); - lumamode->show (); - lumamodeConn = lumamode->signal_toggled().connect( sigc::mem_fun(*this, &ColorToning::lumamodeChanged) ); - - pack_start (*lumamode); - - - redlow->setAdjusterListener (this); - greenlow->setAdjusterListener (this); - bluelow->setAdjusterListener (this); - balance->setAdjusterListener (this); - redmed->setAdjusterListener (this); - greenmed->setAdjusterListener (this); - bluemed->setAdjusterListener (this); - redhigh->setAdjusterListener (this); - greenhigh->setAdjusterListener (this); - bluehigh->setAdjusterListener (this); - - show_all(); - - disableListener(); - methodChanged(); - enableListener(); -} - -ColorToning::~ColorToning() { - delete colorCurveEditorG; - delete opacityCurveEditorG; - delete clCurveEditorG; - delete cl2CurveEditorG; -} - -/* -void ColorToning::neutralCurves_pressed () { - disableListener(); - - bool changed = false; - changed |= colorShape->reset(); - changed |= opacityShape->reset(); - changed |= clshape->reset(); - changed |= cl2shape->reset(); - - enableListener(); - - if (listener && enabled->get_active() && changed) - listener->panelChanged (EvColorToningNeutralcur, M("ADJUSTER_RESET_TO_DEFAULT")); -} -*/ - -// Will only reset the chanel mixer -void ColorToning::neutral_pressed () { - disableListener(); - redlow->resetValue(false); - greenlow->resetValue(false); - bluelow->resetValue(false); - redmed->resetValue(false); - greenmed->resetValue(false); - bluemed->resetValue(false); - redhigh->resetValue(false); - greenhigh->resetValue(false); - bluehigh->resetValue(false); - //balance->resetValue(false); - - enableListener(); - if (listener && getEnabled()) - listener->panelChanged (EvColorToningNeutral, M("ADJUSTER_RESET_TO_DEFAULT")); -} - -void ColorToning::read (const ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - methodconn.block(true); - twocconn.block(true); - colorShape->setCurve (pp->colorToning.colorCurve); - opacityShape->setCurve (pp->colorToning.opacityCurve); - clshape->setCurve (pp->colorToning.clcurve); - cl2shape->setCurve (pp->colorToning.cl2curve); - - if (pedited) { - redlow->setEditedState (pedited->colorToning.redlow ? Edited : UnEdited); - greenlow->setEditedState (pedited->colorToning.greenlow ? Edited : UnEdited); - bluelow->setEditedState (pedited->colorToning.bluelow ? Edited : UnEdited); - balance->setEditedState (pedited->colorToning.balance ? Edited : UnEdited); - redmed->setEditedState (pedited->colorToning.redmed ? Edited : UnEdited); - greenmed->setEditedState (pedited->colorToning.greenmed ? Edited : UnEdited); - bluemed->setEditedState (pedited->colorToning.bluemed ? Edited : UnEdited); - redhigh->setEditedState (pedited->colorToning.redhigh ? Edited : UnEdited); - greenhigh->setEditedState (pedited->colorToning.greenhigh ? Edited : UnEdited); - bluehigh->setEditedState (pedited->colorToning.bluehigh ? Edited : UnEdited); - - hlColSat->setEditedState (pedited->colorToning.hlColSat ? Edited : UnEdited); - shadowsColSat->setEditedState (pedited->colorToning.shadowsColSat ? Edited : UnEdited); - - set_inconsistent (multiImage && !pedited->colorToning.enabled); - colorShape->setUnChanged (!pedited->colorToning.colorCurve); - opacityShape->setUnChanged (!pedited->colorToning.opacityCurve); - autosat->set_inconsistent (!pedited->colorToning.autosat); - clshape->setUnChanged (!pedited->colorToning.clcurve); - cl2shape->setUnChanged (!pedited->colorToning.cl2curve); - lumamode->set_inconsistent (!pedited->colorToning.lumamode); - } - redlow->setValue (pp->colorToning.redlow); - greenlow->setValue (pp->colorToning.greenlow); - bluelow->setValue (pp->colorToning.bluelow); - balance->setValue (pp->colorToning.balance); - redmed->setValue (pp->colorToning.redmed); - greenmed->setValue (pp->colorToning.greenmed); - bluemed->setValue (pp->colorToning.bluemed); - redhigh->setValue (pp->colorToning.redhigh); - greenhigh->setValue (pp->colorToning.greenhigh); - bluehigh->setValue (pp->colorToning.bluehigh); - - setEnabled (pp->colorToning.enabled); - - autosatConn.block (true); - autosat->set_active (pp->colorToning.autosat); - autosatConn.block (false); - lastautosat = pp->colorToning.autosat; - - satProtectionThreshold->setValue (pp->colorToning.satProtectionThreshold); - saturatedOpacity->setValue (pp->colorToning.saturatedOpacity); - hlColSat->setValue (pp->colorToning.hlColSat); - shadowsColSat->setValue (pp->colorToning.shadowsColSat); - strength->setValue (pp->colorToning.strength); - lumamodeConn.block (true); - lumamode->set_active (pp->colorToning.lumamode); - lumamodeConn.block (false); - - lastLumamode = pp->colorToning.lumamode; - - if (pedited && !pedited->colorToning.method) - method->set_active (5); - else if (pp->colorToning.method=="Lab") - method->set_active (0); - else if (pp->colorToning.method=="RGBSliders") - method->set_active (1); - else if (pp->colorToning.method=="RGBCurves") - method->set_active (2); - else if (pp->colorToning.method=="Splitco") - method->set_active (3); - else if (pp->colorToning.method=="Splitlr") - method->set_active (4); - methodChanged(); - methodconn.block(false); - - - if (pedited && !pedited->colorToning.twocolor) - twocolor->set_active (4); - else if (pp->colorToning.twocolor=="Std") - twocolor->set_active (0); - else if (pp->colorToning.twocolor=="All") - twocolor->set_active (1); - else if (pp->colorToning.twocolor=="Separ") - twocolor->set_active (2); - else if (pp->colorToning.twocolor=="Two") - twocolor->set_active (3); - - twocolorChanged(true); - - twocconn.block(false); - - enableListener (); -} - -void ColorToning::write (ProcParams* pp, ParamsEdited* pedited) { - pp->colorToning.redlow = redlow->getValue (); - pp->colorToning.greenlow = greenlow->getValue (); - pp->colorToning.bluelow = bluelow->getValue (); - pp->colorToning.balance = balance->getIntValue (); - pp->colorToning.redmed = redmed->getValue (); - pp->colorToning.greenmed = greenmed->getValue (); - pp->colorToning.bluemed = bluemed->getValue (); - pp->colorToning.redhigh = redhigh->getValue (); - pp->colorToning.greenhigh = greenhigh->getValue (); - pp->colorToning.bluehigh = bluehigh->getValue (); - - pp->colorToning.enabled = getEnabled(); - pp->colorToning.colorCurve = colorShape->getCurve (); - pp->colorToning.opacityCurve = opacityShape->getCurve (); - pp->colorToning.clcurve = clshape->getCurve (); - pp->colorToning.cl2curve = cl2shape->getCurve (); - pp->colorToning.lumamode = lumamode->get_active(); - - pp->colorToning.hlColSat = hlColSat->getValue (); - pp->colorToning.shadowsColSat = shadowsColSat->getValue (); - pp->colorToning.autosat = autosat->get_active(); - pp->colorToning.satProtectionThreshold = satProtectionThreshold->getIntValue(); - pp->colorToning.saturatedOpacity = saturatedOpacity->getIntValue(); - pp->colorToning.strength = strength->getIntValue(); - - if (pedited) { - pedited->colorToning.redlow = redlow->getEditedState (); - pedited->colorToning.greenlow = greenlow->getEditedState (); - pedited->colorToning.bluelow = bluelow->getEditedState (); - pedited->colorToning.balance = balance->getEditedState (); - pedited->colorToning.redmed = redmed->getEditedState (); - pedited->colorToning.greenmed = greenmed->getEditedState (); - pedited->colorToning.bluemed = bluemed->getEditedState (); - pedited->colorToning.redhigh = redhigh->getEditedState (); - pedited->colorToning.greenhigh = greenhigh->getEditedState (); - pedited->colorToning.bluehigh = bluehigh->getEditedState (); - pedited->colorToning.method = method->get_active_text()!=M("GENERAL_UNCHANGED"); - pedited->colorToning.twocolor = twocolor->get_active_text()!=M("GENERAL_UNCHANGED"); - - pedited->colorToning.enabled = !get_inconsistent(); - pedited->colorToning.autosat = !autosat->get_inconsistent(); - pedited->colorToning.colorCurve = !colorShape->isUnChanged (); - pedited->colorToning.opacityCurve = !opacityShape->isUnChanged (); - pedited->colorToning.clcurve = !clshape->isUnChanged (); - pedited->colorToning.cl2curve = !cl2shape->isUnChanged (); - pedited->colorToning.lumamode = !lumamode->get_inconsistent(); - - pedited->colorToning.hlColSat = hlColSat->getEditedState (); - pedited->colorToning.shadowsColSat = shadowsColSat->getEditedState (); - } - - if (method->get_active_row_number()==0) - pp->colorToning.method = "Lab"; - else if (method->get_active_row_number()==1) - pp->colorToning.method = "RGBSliders"; - else if (method->get_active_row_number()==2) - pp->colorToning.method = "RGBCurves"; - else if (method->get_active_row_number()==3) - pp->colorToning.method = "Splitco"; - else if (method->get_active_row_number()==4) - pp->colorToning.method = "Splitlr"; - - if (twocolor->get_active_row_number()==0) - pp->colorToning.twocolor = "Std"; - else if (twocolor->get_active_row_number()==1) - pp->colorToning.twocolor = "All"; - else if (twocolor->get_active_row_number()==2) - pp->colorToning.twocolor = "Separ"; - else if (twocolor->get_active_row_number()==3) - pp->colorToning.twocolor = "Two"; -} - -void ColorToning::lumamodeChanged () { - - if (batchMode) { - if (lumamode->get_inconsistent()) { - lumamode->set_inconsistent (false); - lumamodeConn.block (true); - lumamode->set_active (false); - lumamodeConn.block (false); - } - else if (lastLumamode) - lumamode->set_inconsistent (true); - - lastLumamode = lumamode->get_active (); - } - - if (listener && getEnabled()) { - if (lumamode->get_active ()) - listener->panelChanged (EvColorToningLumamode, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvColorToningLumamode, M("GENERAL_DISABLED")); - } -} - -void ColorToning::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - - redlow->setDefault (defParams->colorToning.redlow); - greenlow->setDefault (defParams->colorToning.greenlow); - bluelow->setDefault (defParams->colorToning.bluelow); - balance->setDefault (defParams->colorToning.balance); - redmed->setDefault (defParams->colorToning.redmed); - greenmed->setDefault (defParams->colorToning.greenmed); - bluemed->setDefault (defParams->colorToning.bluemed); - redhigh->setDefault (defParams->colorToning.redhigh); - greenhigh->setDefault (defParams->colorToning.greenhigh); - bluehigh->setDefault (defParams->colorToning.bluehigh); - satProtectionThreshold->setDefault (defParams->colorToning.satProtectionThreshold); - saturatedOpacity->setDefault (defParams->colorToning.saturatedOpacity); - hlColSat->setDefault (defParams->colorToning.hlColSat); - shadowsColSat->setDefault (defParams->colorToning.shadowsColSat); - strength->setDefault (defParams->colorToning.strength); - - if (pedited) { - redlow->setDefaultEditedState (pedited->colorToning.redlow ? Edited : UnEdited); - greenlow->setDefaultEditedState (pedited->colorToning.greenlow ? Edited : UnEdited); - bluelow->setDefaultEditedState (pedited->colorToning.bluelow ? Edited : UnEdited); - balance->setDefaultEditedState (pedited->colorToning.balance ? Edited : UnEdited); - redmed->setDefaultEditedState (pedited->colorToning.redmed ? Edited : UnEdited); - greenmed->setDefaultEditedState (pedited->colorToning.greenmed ? Edited : UnEdited); - bluemed->setDefaultEditedState (pedited->colorToning.bluemed ? Edited : UnEdited); - redhigh->setDefaultEditedState (pedited->colorToning.redhigh ? Edited : UnEdited); - greenhigh->setDefaultEditedState (pedited->colorToning.greenhigh ? Edited : UnEdited); - bluehigh->setDefaultEditedState (pedited->colorToning.bluehigh ? Edited : UnEdited); - satProtectionThreshold->setDefaultEditedState (pedited->colorToning.satprotectionthreshold ? Edited : UnEdited); - saturatedOpacity->setDefaultEditedState (pedited->colorToning.saturatedopacity ? Edited : UnEdited); - hlColSat->setDefaultEditedState (pedited->colorToning.hlColSat ? Edited : UnEdited); - shadowsColSat->setDefaultEditedState (pedited->colorToning.shadowsColSat ? Edited : UnEdited); - strength->setDefaultEditedState (pedited->colorToning.strength ? Edited : UnEdited); - } - else { - redlow->setDefaultEditedState (Irrelevant); - greenlow->setDefaultEditedState (Irrelevant); - bluelow->setDefaultEditedState (Irrelevant); - balance->setDefaultEditedState (Irrelevant); - redmed->setDefaultEditedState (Irrelevant); - greenmed->setDefaultEditedState (Irrelevant); - bluemed->setDefaultEditedState (Irrelevant); - redhigh->setDefaultEditedState (Irrelevant); - greenhigh->setDefaultEditedState (Irrelevant); - bluehigh->setDefaultEditedState (Irrelevant); - satProtectionThreshold->setDefaultEditedState (Irrelevant); - saturatedOpacity->setDefaultEditedState (Irrelevant); - hlColSat->setDefaultEditedState (Irrelevant); - shadowsColSat->setDefaultEditedState (Irrelevant); - strength->setDefaultEditedState (Irrelevant); - } -} - -void ColorToning::setAdjusterBehavior (bool splitAdd, bool satThresholdAdd, bool satOpacityAdd, bool strprotectAdd, bool balanceAdd) { - redlow->setAddMode(splitAdd); - greenlow->setAddMode(splitAdd); - bluelow->setAddMode(splitAdd); - balance->setAddMode(splitAdd); - redmed->setAddMode(splitAdd); - greenmed->setAddMode(splitAdd); - bluemed->setAddMode(splitAdd); - redhigh->setAddMode(splitAdd); - greenhigh->setAddMode(splitAdd); - bluehigh->setAddMode(splitAdd); - satProtectionThreshold->setAddMode(satThresholdAdd); - saturatedOpacity->setAddMode(satOpacityAdd); - balance->setAddMode(balanceAdd); - strength->setAddMode(strprotectAdd); - -} - -void ColorToning::adjusterChanged (ThresholdAdjuster* a, double newBottom, double newTop) { - if (listener && getEnabled()) - listener->panelChanged (a==hlColSat ? EvColorToningHighights : EvColorToningShadows, - Glib::ustring::compose(Glib::ustring(M("TP_COLORTONING_HUE")+": %1"+"\n"+M("TP_COLORTONING_STRENGTH")+": %2"), int(newTop), int(newBottom))); -} - -int CTChanged_UI (void* data) { - GThreadLock lock; - (static_cast(data))->CTComp_ (); - return 0; -} - - -void ColorToning::autoColorTonChanged(int bwct, int satthres, int satprot){ - nextbw = bwct; - nextsatth=satthres; - nextsatpr=satprot; - g_idle_add (CTChanged_UI, this); -} - -bool ColorToning::CTComp_ () { - - disableListener (); - saturatedOpacity->setValue (nextsatpr); - satProtectionThreshold->setValue (nextsatth); -/* if(nextbw==1) { - saturatedOpacity->show(); - satProtectionThreshold->show(); - autosat->show(); - } - else { - saturatedOpacity->hide(); - satProtectionThreshold->hide(); - autosat->hide(); - } -*/ - enableListener (); - - return false; -} - -void ColorToning::adjusterChanged (Adjuster* a, double newval) { - - if (!listener || !getEnabled()) - return; - - if (a==redlow) - listener->panelChanged (EvColorToningredlow, redlow->getTextValue()); - else if (a==greenlow) - listener->panelChanged (EvColorToninggreenlow, greenlow->getTextValue()); - else if (a==bluelow) - listener->panelChanged (EvColorToningbluelow, bluelow->getTextValue()); - else if (a==redmed) - listener->panelChanged (EvColorToningredmed, redmed->getTextValue()); - else if (a==greenmed) - listener->panelChanged (EvColorToninggreenmed, greenmed->getTextValue()); - else if (a==bluemed) - listener->panelChanged (EvColorToningbluemed, bluemed->getTextValue()); - else if (a==redhigh) - listener->panelChanged (EvColorToningredhigh, redhigh->getTextValue()); - else if (a==greenhigh) - listener->panelChanged (EvColorToninggreenhigh, greenhigh->getTextValue()); - else if (a==bluehigh) - listener->panelChanged (EvColorToningbluehigh, bluehigh->getTextValue()); - else if (a==balance) - listener->panelChanged (EvColorToningbalance, balance->getTextValue()); - else if (a==satProtectionThreshold) - listener->panelChanged (EvColorToningSatThreshold, a->getTextValue()); - else if (a==saturatedOpacity) - listener->panelChanged (EvColorToningSatProtection, a->getTextValue()); - else if (a==strength) - listener->panelChanged (EvColorToningStrength, a->getTextValue()); -} - -//Two Color changed -void ColorToning::twocolorChanged (bool changedbymethod) { - if (!batchMode) { - if(method->get_active_row_number()==0) { // Lab - if(twocolor->get_active_row_number()==0) { - colorCurveEditorG->show(); // visible - opacityCurveEditorG->show(); // visible - clCurveEditorG->hide(); - cl2CurveEditorG->hide(); - } - else if(twocolor->get_active_row_number()==1 || twocolor->get_active_row_number()==3) { - colorCurveEditorG->show(); // visible - opacityCurveEditorG->hide(); - clCurveEditorG->show(); // visible - cl2CurveEditorG->hide(); - irg->hide(); - - } - else if(twocolor->get_active_row_number()==2) { - colorCurveEditorG->show(); // visible - opacityCurveEditorG->hide(); - clCurveEditorG->show(); // visible - cl2CurveEditorG->show(); // visible - irg->show(); - } - } - else if(method->get_active_row_number()==1) { // RGB Sliders - colorCurveEditorG->hide(); - opacityCurveEditorG->hide(); - clCurveEditorG->hide(); - cl2CurveEditorG->hide(); - } - else if(method->get_active_row_number()==2) { // RGB Curves - colorCurveEditorG->show(); // visible - opacityCurveEditorG->show(); // visible - clCurveEditorG->hide(); - cl2CurveEditorG->hide(); - } - else if(method->get_active_row_number()==3) { // Split LR - colorCurveEditorG->hide(); - opacityCurveEditorG->hide(); - clCurveEditorG->hide(); - cl2CurveEditorG->hide(); - } - else if(method->get_active_row_number()==4) { // Split color - colorCurveEditorG->hide(); - opacityCurveEditorG->hide(); - clCurveEditorG->hide(); - cl2CurveEditorG->hide(); - } - } - - if (listener && getEnabled() && !changedbymethod) - listener->panelChanged (EvColorToningTwocolor, twocolor->get_active_text ()); -} - -void ColorToning::twoColorChangedByGui() { - twocolorChanged(false); -} - -void ColorToning::methodChanged () { - - if (!batchMode) { - if (method->get_active_row_number()==0) { // Lab - colorSep->show(); - colLabel->hide(); - interLabel->hide(); - colorCurveEditorG->show(); - twocolor->show(); - opacityCurveEditorG->hide(); - clCurveEditorG->hide(); - cl2CurveEditorG->hide(); - //neutralCurves->show(); - hlColSat->hide(); - shadowsColSat->hide(); - balance->hide(); -// satLimiterSep->show(); - if(autosat->get_active()) { - saturatedOpacity->set_sensitive(false); - satProtectionThreshold->set_sensitive(false); - satProtectionThreshold->show(); - saturatedOpacity->show(); - } - else { - satProtectionThreshold->show(); - saturatedOpacity->show(); - saturatedOpacity->set_sensitive(true); - satProtectionThreshold->set_sensitive(true); - } - autosat->show(); - p1Frame->show(); - - strength->hide(); - chanMixerBox->hide(); - neutrHBox->hide(); - lumamode->hide(); - //splitSep->hide(); - //satlow->hide(); - //sathigh->hide(); - - twocolorChanged(true); - } - else if (method->get_active_row_number()==1) { // RGB Sliders - colorSep->hide(); - colLabel->hide(); - interLabel->hide(); - colorCurveEditorG->hide(); - twocolor->hide(); - twocolor->set_active (false); - opacityCurveEditorG->hide(); - clCurveEditorG->hide(); - cl2CurveEditorG->hide(); - //neutralCurves->hide(); - hlColSat->show(); - shadowsColSat->show(); - balance->show(); -// satLimiterSep->show(); - autosat->show(); - p1Frame->show(); - if(autosat->get_active()) { - saturatedOpacity->set_sensitive(false); - satProtectionThreshold->set_sensitive(false); - satProtectionThreshold->show(); - saturatedOpacity->show(); - } - else { - satProtectionThreshold->show(); - saturatedOpacity->show(); - saturatedOpacity->set_sensitive(true); - satProtectionThreshold->set_sensitive(true); - } - - strength->hide(); - chanMixerBox->hide(); - neutrHBox->hide(); - lumamode->hide(); - - } - else if (method->get_active_row_number()==2) { // RGB Curves - colorSep->hide(); - colLabel->hide(); - interLabel->hide(); - colorCurveEditorG->show(); - twocolor->hide(); - twocolor->set_active (false); - opacityCurveEditorG->show(); - clCurveEditorG->hide(); - cl2CurveEditorG->hide(); - //neutralCurves->show(); - hlColSat->hide(); - shadowsColSat->hide(); - balance->hide(); -// satLimiterSep->show(); - p1Frame->show(); - - autosat->show(); - if(autosat->get_active()) { - saturatedOpacity->set_sensitive(false); - satProtectionThreshold->set_sensitive(false); - satProtectionThreshold->show(); - saturatedOpacity->show(); - } - else { - satProtectionThreshold->show(); - saturatedOpacity->show(); - saturatedOpacity->set_sensitive(true); - satProtectionThreshold->set_sensitive(true); - } - strength->hide(); - chanMixerBox->hide(); - neutrHBox->hide(); - lumamode->hide(); - } - else if (method->get_active_row_number()==3) { // Split LR - colorSep->hide(); - colLabel->hide(); - interLabel->hide(); - colorCurveEditorG->hide(); - twocolor->hide(); - twocolor->set_active (false); - opacityCurveEditorG->hide(); - clCurveEditorG->hide(); - cl2CurveEditorG->hide(); - //neutralCurves->hide(); - hlColSat->hide(); - shadowsColSat->hide(); - balance->hide(); - p1Frame->hide(); - -// satLimiterSep->hide(); - autosat->hide(); - satProtectionThreshold->hide(); - saturatedOpacity->hide(); - strength->show(); - chanMixerBox->show(); - neutrHBox->show(); - lumamode->show(); - } - else if (method->get_active_row_number()==4) { // Split Color - colorSep->show(); - colLabel->hide(); - interLabel->hide(); - colorCurveEditorG->hide(); - twocolor->hide(); - opacityCurveEditorG->hide(); - clCurveEditorG->hide(); - cl2CurveEditorG->hide(); - //neutralCurves->hide(); - hlColSat->show(); - shadowsColSat->show(); - balance->show(); -// satLimiterSep->hide(); - p1Frame->hide(); - - autosat->hide(); - satProtectionThreshold->hide(); - saturatedOpacity->hide(); - strength->show(); - - chanMixerBox->hide(); - neutrHBox->hide(); - lumamode->show(); - } - } - - if (listener && getEnabled()) - listener->panelChanged (EvColorToningMethod, method->get_active_text ()); -} - - -void ColorToning::autoOpenCurve () { - colorShape->openIfNonlinear(); - opacityShape->openIfNonlinear(); - clshape->openIfNonlinear(); - cl2shape->openIfNonlinear(); -} - -void ColorToning::colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller) { - - float R, G, B; - if (callerId == 1) { // ch - main curve - Color::hsv2rgb01(float(valY), 1.0f, 0.5f, R, G, B); - } - else if (callerId == 2) { // Slider 1 background - if (valY > 0.5) - // the hue range - Color::hsv2rgb01(float(valX), 1.0f, 0.5f, R, G, B); - else { - // the strength applied to the current hue - double strength, hue; - float r_, g_, b_; - hlColSat->getValue(strength, hue); - Color::hsv2rgb01(valY*2.f, 1.f, 1.f, r_, g_, b_); - Color::hsv2rgb01(hue/360.f, 1.f, 1.f, R, G, B); - R = r_+(R-r_)*valX; - G = g_+(G-g_)*valX; - B = b_+(B-b_)*valX; - } - } - else if (callerId == 3) { // Slider 2 background - if (valY > 0.5) - // the hue range - Color::hsv2rgb01(float(valX), 1.0f, 0.5f, R, G, B); - else { - // the strength applied to the current hue - double strength, hue; - float r_, g_, b_; - shadowsColSat->getValue(strength, hue); - Color::hsv2rgb01(valY*2.f, 1.f, 1.f, r_, g_, b_); - Color::hsv2rgb01(hue/360.f, 1.f, 1.f, R, G, B); - R = r_+(R-r_)*valX; - G = g_+(G-g_)*valX; - B = b_+(B-b_)*valX; - } - } - caller->ccRed = double(R); - caller->ccGreen = double(G); - caller->ccBlue = double(B); -} - -void ColorToning::curveChanged (CurveEditor* ce) { - - if (listener && getEnabled()) { - if (ce == colorShape) - listener->panelChanged (EvColorToningColor, M("HISTORY_CUSTOMCURVE")); - else if (ce == opacityShape) - listener->panelChanged (EvColorToningOpacity, M("HISTORY_CUSTOMCURVE")); - else if (ce == clshape) - listener->panelChanged (EvColorToningCLCurve, M("HISTORY_CUSTOMCURVE")); - else if (ce == cl2shape) - listener->panelChanged (EvColorToningLLCurve, M("HISTORY_CUSTOMCURVE")); - } -} - -void ColorToning::enabledChanged () { - - if (listener) { - if (get_inconsistent()) - listener->panelChanged (EvColorToningEnabled, M("GENERAL_UNCHANGED")); - else if (getEnabled()) - listener->panelChanged (EvColorToningEnabled, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvColorToningEnabled, M("GENERAL_DISABLED")); - } -} - -void ColorToning::autosatChanged () { - - if (batchMode) { - if (autosat->get_inconsistent()) { - autosat->set_inconsistent (false); - autosatConn.block (true); - autosat->set_active (false); - autosatConn.block (false); - } - else if (lastautosat) - autosat->set_inconsistent (true); - - lastautosat = autosat->get_active (); - } - if (listener) { - if (autosat->get_active()) { - if (getEnabled()) - listener->panelChanged (EvColorToningautosat, M("GENERAL_ENABLED")); - saturatedOpacity->set_sensitive(false); - satProtectionThreshold->set_sensitive(false); - } - else { - if (getEnabled()) - listener->panelChanged (EvColorToningautosat, M("GENERAL_DISABLED")); - saturatedOpacity->set_sensitive(true); - satProtectionThreshold->set_sensitive(true); - } - - } -} - -void ColorToning::trimValues (rtengine::procparams::ProcParams* pp) { - - redlow->trimValue(pp->colorToning.redlow); - greenlow->trimValue(pp->colorToning.greenlow); - bluelow->trimValue(pp->colorToning.bluelow); - balance->trimValue(pp->colorToning.balance); - redmed->trimValue(pp->colorToning.redmed); - greenmed->trimValue(pp->colorToning.greenmed); - bluemed->trimValue(pp->colorToning.bluemed); - redhigh->trimValue(pp->colorToning.redhigh); - greenhigh->trimValue(pp->colorToning.greenhigh); - bluehigh->trimValue(pp->colorToning.bluehigh); -} - -void ColorToning::setBatchMode (bool batchMode) -{ - ToolPanel::setBatchMode (batchMode); - method->append_text (M("GENERAL_UNCHANGED")); - twocolor->append_text (M("GENERAL_UNCHANGED")); - hlColSat->showEditedCB (); - shadowsColSat->showEditedCB (); - redlow->showEditedCB (); - greenlow->showEditedCB (); - bluelow->showEditedCB (); - balance->showEditedCB (); - redmed->showEditedCB (); - greenmed->showEditedCB (); - bluemed->showEditedCB (); - redhigh->showEditedCB (); - greenhigh->showEditedCB (); - bluehigh->showEditedCB (); - - colorCurveEditorG->setBatchMode (batchMode); - opacityCurveEditorG->setBatchMode (batchMode); - clCurveEditorG->setBatchMode (batchMode); - cl2CurveEditorG->setBatchMode (batchMode); - -} +/* + * This file is part of RawTherapee. + */ +#include "colortoning.h" +#include "mycurve.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +ColorToning::ColorToning () : FoldableToolPanel(this, "colortoning", M("TP_COLORTONING_LABEL"), false, true) +{ + nextbw=0; + CurveListener::setMulti(true); + + //---------------method + + method = Gtk::manage (new MyComboBoxText ()); + method->append_text (M("TP_COLORTONING_LAB")); + method->append_text (M("TP_COLORTONING_RGBSLIDERS")); + method->append_text (M("TP_COLORTONING_RGBCURVES")); + method->append_text (M("TP_COLORTONING_SPLITCOCO")); + method->append_text (M("TP_COLORTONING_SPLITLR")); + method->set_active (0); + method->set_tooltip_text (M("TP_COLORTONING_METHOD_TOOLTIP")); + + ctbox = Gtk::manage (new Gtk::HBox ()); + Gtk::Label* lab = Gtk::manage (new Gtk::Label (M("TP_COLORTONING_METHOD"))); + ctbox->pack_start (*lab, Gtk::PACK_SHRINK, 4); + ctbox->pack_start (*method); + pack_start (*ctbox); + + methodconn = method->signal_changed().connect ( sigc::mem_fun(*this, &ColorToning::methodChanged) ); + + //----------- Color curve ------------------------------ + + colorSep = Gtk::manage (new Gtk::HSeparator()); + pack_start (*colorSep); + + colLabel = Gtk::manage (new Gtk::Label (M("TP_COLORTONING_LABCOL"))); + colLabel->set_tooltip_text (M("TP_COLORTONING_LABCOL_TOOLTIP")); + + interLabel = Gtk::manage (new Gtk::Label (M("TP_COLORTONING_LABINT"))); + interLabel->set_tooltip_text (M("TP_COLORTONING_LABINT_TOOLTIP")); + pack_start (*colLabel, Gtk::PACK_SHRINK, 4); + pack_start (*interLabel, Gtk::PACK_SHRINK, 4); + + colorCurveEditorG = new CurveEditorGroup (options.lastColorToningCurvesDir, M("TP_COLORTONING_COLOR")); + colorCurveEditorG->setCurveListener (this); + + colorShape = static_cast(colorCurveEditorG->addCurve(CT_Flat, "", NULL, false)); + colorShape->setCurveColorProvider(this, 1); + std::vector milestones; + // whole hue range + for (int i=0; i<7; i++) { + float R, G, B; + float x = float(i)*(1.0f/6.0); + Color::hsv2rgb01(x, 0.5f, 0.5f, R, G, B); + milestones.push_back( GradientMilestone(double(x), double(R), double(G), double(B)) ); + } + colorShape->setLeftBarBgGradient(milestones); + + // luminance gradient + milestones.clear(); + milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); + milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); + colorShape->setBottomBarBgGradient(milestones); + std::vector defaultCurve; + rtengine::ColorToningParams::getDefaultColorCurve(defaultCurve); + colorShape->setResetCurve(FCT_MinMaxCPoints, defaultCurve); + + // This will add the reset button at the end of the curveType buttons + colorCurveEditorG->curveListComplete(); + colorCurveEditorG->show(); + + pack_start( *colorCurveEditorG, Gtk::PACK_SHRINK, 2); + + //----------------------red green blue yellow colours + + twocolor = Gtk::manage (new MyComboBoxText ()); + twocolor->append_text (M("TP_COLORTONING_TWOSTD")); + twocolor->append_text (M("TP_COLORTONING_TWOALL")); + twocolor->append_text (M("TP_COLORTONING_TWOBY")); + twocolor->append_text (M("TP_COLORTONING_TWO2")); + twocolor->set_tooltip_text (M("TP_COLORTONING_TWOCOLOR_TOOLTIP")); + twocolor->set_active (0); + + twocconn = twocolor->signal_changed().connect( sigc::mem_fun(*this, &ColorToning::twoColorChangedByGui) ); + + pack_start (*twocolor, Gtk::PACK_SHRINK, 4); + + //----------- Opacity curve ------------------------------ + + opacityCurveEditorG = new CurveEditorGroup (options.lastColorToningCurvesDir, M("TP_COLORTONING_OPACITY")); + opacityCurveEditorG->setCurveListener (this); + + rtengine::ColorToningParams::getDefaultOpacityCurve(defaultCurve); + opacityShape = static_cast(opacityCurveEditorG->addCurve(CT_Flat, "", NULL, false)); + opacityShape->setIdentityValue(0.); + opacityShape->setResetCurve(FlatCurveType(defaultCurve.at(0)), defaultCurve); + opacityShape->setBottomBarBgGradient(milestones); + + // This will add the reset button at the end of the curveType buttons + opacityCurveEditorG->curveListComplete(); + opacityCurveEditorG->show(); + + pack_start( *opacityCurveEditorG, Gtk::PACK_SHRINK, 2); + + //---------Chroma curve 1 -------------------- + iby = Gtk::manage (new RTImage ("Chanmixer-BY.png")); + irg = Gtk::manage (new RTImage ("Chanmixer-RG.png")); + + clCurveEditorG = new CurveEditorGroup (options.lastColorToningCurvesDir, M("TP_COLORTONING_CHROMAC")); + clCurveEditorG->setCurveListener (this); + + rtengine::ColorToningParams::getDefaultCLCurve(defaultCurve); + clshape = static_cast(clCurveEditorG->addCurve(CT_Diagonal, M("TP_COLORTONING_AB"),irg)); + clshape->setResetCurve(DiagonalCurveType(defaultCurve.at(0)), defaultCurve); + clshape->setTooltip(M("TP_COLORTONING_CURVEEDITOR_CL_TOOLTIP")); + + clshape->setLeftBarColorProvider(this, 1); + clshape->setRangeDefaultMilestones(0.25, 0.5, 0.75); + milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); + milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); + + clshape->setBottomBarBgGradient(milestones); + clCurveEditorG->curveListComplete(); + + pack_start( *clCurveEditorG, Gtk::PACK_SHRINK, 2); + + //---------Chroma curve 2 -------------------- + + cl2CurveEditorG = new CurveEditorGroup (options.lastColorToningCurvesDir, M("TP_COLORTONING_CHROMAC")); + cl2CurveEditorG->setCurveListener (this); + + rtengine::ColorToningParams::getDefaultCL2Curve(defaultCurve); + cl2shape = static_cast(cl2CurveEditorG->addCurve(CT_Diagonal, M("TP_COLORTONING_BY"),iby)); + cl2shape->setResetCurve(DiagonalCurveType(defaultCurve.at(0)), defaultCurve); + cl2shape->setTooltip(M("TP_COLORTONING_CURVEEDITOR_CL_TOOLTIP")); + + cl2shape->setLeftBarColorProvider(this, 1); + cl2shape->setRangeDefaultMilestones(0.25, 0.5, 0.75); + milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); + milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); + + cl2shape->setBottomBarBgGradient(milestones); + cl2CurveEditorG->curveListComplete(); + + pack_start( *cl2CurveEditorG, Gtk::PACK_SHRINK, 2); + + //--------------------- Reset curves ----------------------------- + /* Each curve can reset to a different curve, so this button only save one click now... so we remove it. + neutralCurves = Gtk::manage (new Gtk::Button (M("TP_COLORTONING_NEUTRALCUR"))); + RTImage *resetImgc = Gtk::manage (new RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.png")); + neutralCurves->set_image(*resetImgc); + neutralCurves->set_tooltip_text (M("TP_COLORTONING_NEUTRALCUR_TIP")); + neutralcurvesconn = neutralCurves->signal_pressed().connect( sigc::mem_fun(*this, &ColorToning::neutralCurves_pressed) ); + neutralCurves->show(); + + pack_start (*neutralCurves); + */ + + //----------- Sliders + balance ------------------------------ + + hlColSat = Gtk::manage (new ThresholdAdjuster (M("TP_COLORTONING_HIGHLIGHT"), 0., 100., 60., M("TP_COLORTONING_STRENGTH"), 1., 0., 360., 80., M("TP_COLORTONING_HUE"), 1., NULL, false)); + hlColSat->setAdjusterListener (this); + hlColSat->setBgColorProvider(this, 2); + hlColSat->setUpdatePolicy(RTUP_DYNAMIC); + + pack_start( *hlColSat, Gtk::PACK_SHRINK, 0); + + shadowsColSat = Gtk::manage (new ThresholdAdjuster (M("TP_COLORTONING_SHADOWS"), 0., 100., 80., M("TP_COLORTONING_STRENGTH"), 1., 0., 360., 208., M("TP_COLORTONING_HUE"), 1., NULL, false)); + shadowsColSat->setAdjusterListener (this); + shadowsColSat->setBgColorProvider(this, 3); + shadowsColSat->setUpdatePolicy(RTUP_DYNAMIC); + + pack_start( *shadowsColSat, Gtk::PACK_SHRINK, 0); + + + balance = Gtk::manage( new Adjuster(M("TP_COLORTONING_BALANCE"), -100., 100., 1., 0.) ); + balance->setAdjusterListener(this); + + pack_start (*balance, Gtk::PACK_SHRINK, 2); + + //----------- Saturation and strength ------------------------------ + +// satLimiterSep = Gtk::manage (new Gtk::HSeparator()); + + +// pack_start (*satLimiterSep, Gtk::PACK_SHRINK); + +// Gtk::Frame *p1Frame; + // Vertical box container for the content of the Process 1 frame + Gtk::VBox *p1VBox; + p1Frame = Gtk::manage (new Gtk::Frame(M("TP_COLORTONING_SA")) ); + p1Frame->set_border_width(0); + p1Frame->set_label_align(0.025, 0.5); + + p1VBox = Gtk::manage ( new Gtk::VBox()); + p1VBox->set_border_width(4); + p1VBox->set_spacing(2); + + autosat = Gtk::manage (new Gtk::CheckButton (M("TP_COLORTONING_AUTOSAT"))); + autosat->set_active (true); + autosatConn = autosat->signal_toggled().connect( sigc::mem_fun(*this, &ColorToning::autosatChanged) ); + //satFrame->set_label_widget(*autosat); + + p1VBox->pack_start (*autosat, Gtk::PACK_SHRINK, 2); + + satProtectionThreshold = Gtk::manage( new Adjuster(M("TP_COLORTONING_SATURATIONTHRESHOLD"), 0., 100., 1., 80.) ); + satProtectionThreshold->setAdjusterListener(this); + satProtectionThreshold->set_sensitive(false); + + p1VBox->pack_start( *satProtectionThreshold, Gtk::PACK_SHRINK, 2); + + saturatedOpacity = Gtk::manage( new Adjuster(M("TP_COLORTONING_SATURATEDOPACITY"), 0., 100., 1., 30.) );; + saturatedOpacity->setAdjusterListener(this); + saturatedOpacity->set_sensitive(false); + + p1VBox->pack_start( *saturatedOpacity, Gtk::PACK_SHRINK, 2); //I have moved after Chanmixer + p1Frame->add(*p1VBox); + pack_start (*p1Frame, Gtk::PACK_EXPAND_WIDGET, 4); + + strength = Gtk::manage( new Adjuster(M("TP_COLORTONING_STR"), 0., 100., 1., 50.) );; + strength->setAdjusterListener(this); + + + + // --------------------Sliders BW Colortoning ------------------- + + chanMixerBox = Gtk::manage (new Gtk::VBox()); + Gtk::VBox *chanMixerHLBox = Gtk::manage (new Gtk::VBox()); + Gtk::VBox *chanMixerMidBox = Gtk::manage (new Gtk::VBox()); + Gtk::VBox *chanMixerShadowsBox = Gtk::manage (new Gtk::VBox()); + + Gtk::Image* iblueR = Gtk::manage (new RTImage ("ajd-wb-temp1.png")); + Gtk::Image* iyelL = Gtk::manage (new RTImage ("ajd-wb-temp2.png")); + Gtk::Image* imagL = Gtk::manage (new RTImage ("ajd-wb-green1.png")); + Gtk::Image* igreenR = Gtk::manage (new RTImage ("ajd-wb-green2.png")); + Gtk::Image* icyanL = Gtk::manage (new RTImage ("ajd-wb-bluered1.png")); + Gtk::Image* iredR = Gtk::manage (new RTImage ("ajd-wb-bluered2.png")); + + Gtk::Image* iblueRm = Gtk::manage (new RTImage ("ajd-wb-temp1.png")); + Gtk::Image* iyelLm = Gtk::manage (new RTImage ("ajd-wb-temp2.png")); + Gtk::Image* imagLm = Gtk::manage (new RTImage ("ajd-wb-green1.png")); + Gtk::Image* igreenRm = Gtk::manage (new RTImage ("ajd-wb-green2.png")); + Gtk::Image* icyanLm = Gtk::manage (new RTImage ("ajd-wb-bluered1.png")); + Gtk::Image* iredRm = Gtk::manage (new RTImage ("ajd-wb-bluered2.png")); + + Gtk::Image* iblueRh = Gtk::manage (new RTImage ("ajd-wb-temp1.png")); + Gtk::Image* iyelLh = Gtk::manage (new RTImage ("ajd-wb-temp2.png")); + Gtk::Image* imagLh = Gtk::manage (new RTImage ("ajd-wb-green1.png")); + Gtk::Image* igreenRh = Gtk::manage (new RTImage ("ajd-wb-green2.png")); + Gtk::Image* icyanLh = Gtk::manage (new RTImage ("ajd-wb-bluered1.png")); + Gtk::Image* iredRh = Gtk::manage (new RTImage ("ajd-wb-bluered2.png")); + + redhigh = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., icyanLh, iredRh )); + greenhigh = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., imagLh , igreenRh)); + bluehigh = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., iyelLh , iblueRh )); + + redmed = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., icyanLm, iredRm )); + greenmed = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., imagLm , igreenRm)); + bluemed = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., iyelLm , iblueRm )); + + redlow = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., icyanL, iredR )); + greenlow = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., imagL , igreenR)); + bluelow = Gtk::manage (new Adjuster ("", -100., 100., 1., 0., iyelL , iblueR )); + + chanMixerHLBox->pack_start (*redhigh); + chanMixerHLBox->pack_start (*greenhigh); + chanMixerHLBox->pack_start (*bluehigh); + chanMixerMidBox->pack_start (*redmed); + chanMixerMidBox->pack_start (*greenmed); + chanMixerMidBox->pack_start (*bluemed); + chanMixerShadowsBox->pack_start (*redlow); + chanMixerShadowsBox->pack_start (*greenlow); + chanMixerShadowsBox->pack_start (*bluelow); + + Gtk::Frame *chanMixerHLFrame = Gtk::manage (new Gtk::Frame(M("TP_COLORTONING_HIGHLIGHT"))); + Gtk::Frame *chanMixerMidFrame = Gtk::manage (new Gtk::Frame(M("TP_COLORTONING_MIDTONES"))); + Gtk::Frame *chanMixerShadowsFrame = Gtk::manage (new Gtk::Frame(M("TP_COLORTONING_SHADOWS"))); + + chanMixerHLFrame->add(*chanMixerHLBox); + chanMixerMidFrame->add(*chanMixerMidBox); + chanMixerShadowsFrame->add(*chanMixerShadowsBox); + + chanMixerBox->pack_start(*chanMixerHLFrame, Gtk::PACK_SHRINK); + chanMixerBox->pack_start(*chanMixerMidFrame, Gtk::PACK_SHRINK); + chanMixerBox->pack_start(*chanMixerShadowsFrame, Gtk::PACK_SHRINK); + + pack_start(*chanMixerBox, Gtk::PACK_SHRINK); + pack_start( *strength, Gtk::PACK_SHRINK, 2); //I have moved after Chanmixer + + //--------------------- Reset sliders --------------------------- + neutrHBox = Gtk::manage (new Gtk::HBox ()); + neutrHBox->set_border_width (2); + + neutral = Gtk::manage (new Gtk::Button (M("TP_COLORTONING_NEUTRAL"))); + RTImage *resetImg = Gtk::manage (new RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.png")); + neutral->set_image(*resetImg); + neutral->set_tooltip_text (M("TP_COLORTONING_NEUTRAL_TIP")); + neutralconn = neutral->signal_pressed().connect( sigc::mem_fun(*this, &ColorToning::neutral_pressed) ); + neutral->show(); + neutrHBox->pack_start (*neutral); + + pack_start (*neutrHBox); + + //--------------------- Keep luminance checkbox ------------------- + lumamode = Gtk::manage (new Gtk::CheckButton (M("TP_COLORTONING_LUMAMODE"))); + lumamode->set_tooltip_markup (M("TP_COLORTONING_LUMAMODE_TOOLTIP")); + lumamode->set_active (false); + lumamode->show (); + lumamodeConn = lumamode->signal_toggled().connect( sigc::mem_fun(*this, &ColorToning::lumamodeChanged) ); + + pack_start (*lumamode); + + + redlow->setAdjusterListener (this); + greenlow->setAdjusterListener (this); + bluelow->setAdjusterListener (this); + balance->setAdjusterListener (this); + redmed->setAdjusterListener (this); + greenmed->setAdjusterListener (this); + bluemed->setAdjusterListener (this); + redhigh->setAdjusterListener (this); + greenhigh->setAdjusterListener (this); + bluehigh->setAdjusterListener (this); + + show_all(); + + disableListener(); + methodChanged(); + enableListener(); +} + +ColorToning::~ColorToning() { + delete colorCurveEditorG; + delete opacityCurveEditorG; + delete clCurveEditorG; + delete cl2CurveEditorG; +} + +/* +void ColorToning::neutralCurves_pressed () { + disableListener(); + + bool changed = false; + changed |= colorShape->reset(); + changed |= opacityShape->reset(); + changed |= clshape->reset(); + changed |= cl2shape->reset(); + + enableListener(); + + if (listener && enabled->get_active() && changed) + listener->panelChanged (EvColorToningNeutralcur, M("ADJUSTER_RESET_TO_DEFAULT")); +} +*/ + +// Will only reset the chanel mixer +void ColorToning::neutral_pressed () { + disableListener(); + redlow->resetValue(false); + greenlow->resetValue(false); + bluelow->resetValue(false); + redmed->resetValue(false); + greenmed->resetValue(false); + bluemed->resetValue(false); + redhigh->resetValue(false); + greenhigh->resetValue(false); + bluehigh->resetValue(false); + //balance->resetValue(false); + + enableListener(); + if (listener && getEnabled()) + listener->panelChanged (EvColorToningNeutral, M("ADJUSTER_RESET_TO_DEFAULT")); +} + +void ColorToning::read (const ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + methodconn.block(true); + twocconn.block(true); + colorShape->setCurve (pp->colorToning.colorCurve); + opacityShape->setCurve (pp->colorToning.opacityCurve); + clshape->setCurve (pp->colorToning.clcurve); + cl2shape->setCurve (pp->colorToning.cl2curve); + + if (pedited) { + redlow->setEditedState (pedited->colorToning.redlow ? Edited : UnEdited); + greenlow->setEditedState (pedited->colorToning.greenlow ? Edited : UnEdited); + bluelow->setEditedState (pedited->colorToning.bluelow ? Edited : UnEdited); + balance->setEditedState (pedited->colorToning.balance ? Edited : UnEdited); + redmed->setEditedState (pedited->colorToning.redmed ? Edited : UnEdited); + greenmed->setEditedState (pedited->colorToning.greenmed ? Edited : UnEdited); + bluemed->setEditedState (pedited->colorToning.bluemed ? Edited : UnEdited); + redhigh->setEditedState (pedited->colorToning.redhigh ? Edited : UnEdited); + greenhigh->setEditedState (pedited->colorToning.greenhigh ? Edited : UnEdited); + bluehigh->setEditedState (pedited->colorToning.bluehigh ? Edited : UnEdited); + + hlColSat->setEditedState (pedited->colorToning.hlColSat ? Edited : UnEdited); + shadowsColSat->setEditedState (pedited->colorToning.shadowsColSat ? Edited : UnEdited); + + set_inconsistent (multiImage && !pedited->colorToning.enabled); + colorShape->setUnChanged (!pedited->colorToning.colorCurve); + opacityShape->setUnChanged (!pedited->colorToning.opacityCurve); + autosat->set_inconsistent (!pedited->colorToning.autosat); + clshape->setUnChanged (!pedited->colorToning.clcurve); + cl2shape->setUnChanged (!pedited->colorToning.cl2curve); + lumamode->set_inconsistent (!pedited->colorToning.lumamode); + } + redlow->setValue (pp->colorToning.redlow); + greenlow->setValue (pp->colorToning.greenlow); + bluelow->setValue (pp->colorToning.bluelow); + balance->setValue (pp->colorToning.balance); + redmed->setValue (pp->colorToning.redmed); + greenmed->setValue (pp->colorToning.greenmed); + bluemed->setValue (pp->colorToning.bluemed); + redhigh->setValue (pp->colorToning.redhigh); + greenhigh->setValue (pp->colorToning.greenhigh); + bluehigh->setValue (pp->colorToning.bluehigh); + + setEnabled (pp->colorToning.enabled); + + autosatConn.block (true); + autosat->set_active (pp->colorToning.autosat); + autosatConn.block (false); + lastautosat = pp->colorToning.autosat; + + satProtectionThreshold->setValue (pp->colorToning.satProtectionThreshold); + saturatedOpacity->setValue (pp->colorToning.saturatedOpacity); + hlColSat->setValue (pp->colorToning.hlColSat); + shadowsColSat->setValue (pp->colorToning.shadowsColSat); + strength->setValue (pp->colorToning.strength); + lumamodeConn.block (true); + lumamode->set_active (pp->colorToning.lumamode); + lumamodeConn.block (false); + + lastLumamode = pp->colorToning.lumamode; + + if (pedited && !pedited->colorToning.method) + method->set_active (5); + else if (pp->colorToning.method=="Lab") + method->set_active (0); + else if (pp->colorToning.method=="RGBSliders") + method->set_active (1); + else if (pp->colorToning.method=="RGBCurves") + method->set_active (2); + else if (pp->colorToning.method=="Splitco") + method->set_active (3); + else if (pp->colorToning.method=="Splitlr") + method->set_active (4); + methodChanged(); + methodconn.block(false); + + + if (pedited && !pedited->colorToning.twocolor) + twocolor->set_active (4); + else if (pp->colorToning.twocolor=="Std") + twocolor->set_active (0); + else if (pp->colorToning.twocolor=="All") + twocolor->set_active (1); + else if (pp->colorToning.twocolor=="Separ") + twocolor->set_active (2); + else if (pp->colorToning.twocolor=="Two") + twocolor->set_active (3); + + twocolorChanged(true); + + twocconn.block(false); + + enableListener (); +} + +void ColorToning::write (ProcParams* pp, ParamsEdited* pedited) { + pp->colorToning.redlow = redlow->getValue (); + pp->colorToning.greenlow = greenlow->getValue (); + pp->colorToning.bluelow = bluelow->getValue (); + pp->colorToning.balance = balance->getIntValue (); + pp->colorToning.redmed = redmed->getValue (); + pp->colorToning.greenmed = greenmed->getValue (); + pp->colorToning.bluemed = bluemed->getValue (); + pp->colorToning.redhigh = redhigh->getValue (); + pp->colorToning.greenhigh = greenhigh->getValue (); + pp->colorToning.bluehigh = bluehigh->getValue (); + + pp->colorToning.enabled = getEnabled(); + pp->colorToning.colorCurve = colorShape->getCurve (); + pp->colorToning.opacityCurve = opacityShape->getCurve (); + pp->colorToning.clcurve = clshape->getCurve (); + pp->colorToning.cl2curve = cl2shape->getCurve (); + pp->colorToning.lumamode = lumamode->get_active(); + + pp->colorToning.hlColSat = hlColSat->getValue (); + pp->colorToning.shadowsColSat = shadowsColSat->getValue (); + pp->colorToning.autosat = autosat->get_active(); + pp->colorToning.satProtectionThreshold = satProtectionThreshold->getIntValue(); + pp->colorToning.saturatedOpacity = saturatedOpacity->getIntValue(); + pp->colorToning.strength = strength->getIntValue(); + + if (pedited) { + pedited->colorToning.redlow = redlow->getEditedState (); + pedited->colorToning.greenlow = greenlow->getEditedState (); + pedited->colorToning.bluelow = bluelow->getEditedState (); + pedited->colorToning.balance = balance->getEditedState (); + pedited->colorToning.redmed = redmed->getEditedState (); + pedited->colorToning.greenmed = greenmed->getEditedState (); + pedited->colorToning.bluemed = bluemed->getEditedState (); + pedited->colorToning.redhigh = redhigh->getEditedState (); + pedited->colorToning.greenhigh = greenhigh->getEditedState (); + pedited->colorToning.bluehigh = bluehigh->getEditedState (); + pedited->colorToning.method = method->get_active_text()!=M("GENERAL_UNCHANGED"); + pedited->colorToning.twocolor = twocolor->get_active_text()!=M("GENERAL_UNCHANGED"); + + pedited->colorToning.enabled = !get_inconsistent(); + pedited->colorToning.autosat = !autosat->get_inconsistent(); + pedited->colorToning.colorCurve = !colorShape->isUnChanged (); + pedited->colorToning.opacityCurve = !opacityShape->isUnChanged (); + pedited->colorToning.clcurve = !clshape->isUnChanged (); + pedited->colorToning.cl2curve = !cl2shape->isUnChanged (); + pedited->colorToning.lumamode = !lumamode->get_inconsistent(); + + pedited->colorToning.hlColSat = hlColSat->getEditedState (); + pedited->colorToning.shadowsColSat = shadowsColSat->getEditedState (); + } + + if (method->get_active_row_number()==0) + pp->colorToning.method = "Lab"; + else if (method->get_active_row_number()==1) + pp->colorToning.method = "RGBSliders"; + else if (method->get_active_row_number()==2) + pp->colorToning.method = "RGBCurves"; + else if (method->get_active_row_number()==3) + pp->colorToning.method = "Splitco"; + else if (method->get_active_row_number()==4) + pp->colorToning.method = "Splitlr"; + + if (twocolor->get_active_row_number()==0) + pp->colorToning.twocolor = "Std"; + else if (twocolor->get_active_row_number()==1) + pp->colorToning.twocolor = "All"; + else if (twocolor->get_active_row_number()==2) + pp->colorToning.twocolor = "Separ"; + else if (twocolor->get_active_row_number()==3) + pp->colorToning.twocolor = "Two"; +} + +void ColorToning::lumamodeChanged () { + + if (batchMode) { + if (lumamode->get_inconsistent()) { + lumamode->set_inconsistent (false); + lumamodeConn.block (true); + lumamode->set_active (false); + lumamodeConn.block (false); + } + else if (lastLumamode) + lumamode->set_inconsistent (true); + + lastLumamode = lumamode->get_active (); + } + + if (listener && getEnabled()) { + if (lumamode->get_active ()) + listener->panelChanged (EvColorToningLumamode, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvColorToningLumamode, M("GENERAL_DISABLED")); + } +} + +void ColorToning::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + redlow->setDefault (defParams->colorToning.redlow); + greenlow->setDefault (defParams->colorToning.greenlow); + bluelow->setDefault (defParams->colorToning.bluelow); + balance->setDefault (defParams->colorToning.balance); + redmed->setDefault (defParams->colorToning.redmed); + greenmed->setDefault (defParams->colorToning.greenmed); + bluemed->setDefault (defParams->colorToning.bluemed); + redhigh->setDefault (defParams->colorToning.redhigh); + greenhigh->setDefault (defParams->colorToning.greenhigh); + bluehigh->setDefault (defParams->colorToning.bluehigh); + satProtectionThreshold->setDefault (defParams->colorToning.satProtectionThreshold); + saturatedOpacity->setDefault (defParams->colorToning.saturatedOpacity); + hlColSat->setDefault (defParams->colorToning.hlColSat); + shadowsColSat->setDefault (defParams->colorToning.shadowsColSat); + strength->setDefault (defParams->colorToning.strength); + + if (pedited) { + redlow->setDefaultEditedState (pedited->colorToning.redlow ? Edited : UnEdited); + greenlow->setDefaultEditedState (pedited->colorToning.greenlow ? Edited : UnEdited); + bluelow->setDefaultEditedState (pedited->colorToning.bluelow ? Edited : UnEdited); + balance->setDefaultEditedState (pedited->colorToning.balance ? Edited : UnEdited); + redmed->setDefaultEditedState (pedited->colorToning.redmed ? Edited : UnEdited); + greenmed->setDefaultEditedState (pedited->colorToning.greenmed ? Edited : UnEdited); + bluemed->setDefaultEditedState (pedited->colorToning.bluemed ? Edited : UnEdited); + redhigh->setDefaultEditedState (pedited->colorToning.redhigh ? Edited : UnEdited); + greenhigh->setDefaultEditedState (pedited->colorToning.greenhigh ? Edited : UnEdited); + bluehigh->setDefaultEditedState (pedited->colorToning.bluehigh ? Edited : UnEdited); + satProtectionThreshold->setDefaultEditedState (pedited->colorToning.satprotectionthreshold ? Edited : UnEdited); + saturatedOpacity->setDefaultEditedState (pedited->colorToning.saturatedopacity ? Edited : UnEdited); + hlColSat->setDefaultEditedState (pedited->colorToning.hlColSat ? Edited : UnEdited); + shadowsColSat->setDefaultEditedState (pedited->colorToning.shadowsColSat ? Edited : UnEdited); + strength->setDefaultEditedState (pedited->colorToning.strength ? Edited : UnEdited); + } + else { + redlow->setDefaultEditedState (Irrelevant); + greenlow->setDefaultEditedState (Irrelevant); + bluelow->setDefaultEditedState (Irrelevant); + balance->setDefaultEditedState (Irrelevant); + redmed->setDefaultEditedState (Irrelevant); + greenmed->setDefaultEditedState (Irrelevant); + bluemed->setDefaultEditedState (Irrelevant); + redhigh->setDefaultEditedState (Irrelevant); + greenhigh->setDefaultEditedState (Irrelevant); + bluehigh->setDefaultEditedState (Irrelevant); + satProtectionThreshold->setDefaultEditedState (Irrelevant); + saturatedOpacity->setDefaultEditedState (Irrelevant); + hlColSat->setDefaultEditedState (Irrelevant); + shadowsColSat->setDefaultEditedState (Irrelevant); + strength->setDefaultEditedState (Irrelevant); + } +} + +void ColorToning::setAdjusterBehavior (bool splitAdd, bool satThresholdAdd, bool satOpacityAdd, bool strprotectAdd, bool balanceAdd) { + redlow->setAddMode(splitAdd); + greenlow->setAddMode(splitAdd); + bluelow->setAddMode(splitAdd); + balance->setAddMode(splitAdd); + redmed->setAddMode(splitAdd); + greenmed->setAddMode(splitAdd); + bluemed->setAddMode(splitAdd); + redhigh->setAddMode(splitAdd); + greenhigh->setAddMode(splitAdd); + bluehigh->setAddMode(splitAdd); + satProtectionThreshold->setAddMode(satThresholdAdd); + saturatedOpacity->setAddMode(satOpacityAdd); + balance->setAddMode(balanceAdd); + strength->setAddMode(strprotectAdd); + +} + +void ColorToning::adjusterChanged (ThresholdAdjuster* a, double newBottom, double newTop) { + if (listener && getEnabled()) + listener->panelChanged (a==hlColSat ? EvColorToningHighights : EvColorToningShadows, + Glib::ustring::compose(Glib::ustring(M("TP_COLORTONING_HUE")+": %1"+"\n"+M("TP_COLORTONING_STRENGTH")+": %2"), int(newTop), int(newBottom))); +} + +int CTChanged_UI (void* data) { + GThreadLock lock; + (static_cast(data))->CTComp_ (); + return 0; +} + + +void ColorToning::autoColorTonChanged(int bwct, int satthres, int satprot){ + nextbw = bwct; + nextsatth=satthres; + nextsatpr=satprot; + g_idle_add (CTChanged_UI, this); +} + +bool ColorToning::CTComp_ () { + + disableListener (); + saturatedOpacity->setValue (nextsatpr); + satProtectionThreshold->setValue (nextsatth); +/* if(nextbw==1) { + saturatedOpacity->show(); + satProtectionThreshold->show(); + autosat->show(); + } + else { + saturatedOpacity->hide(); + satProtectionThreshold->hide(); + autosat->hide(); + } +*/ + enableListener (); + + return false; +} + +void ColorToning::adjusterChanged (Adjuster* a, double newval) { + + if (!listener || !getEnabled()) + return; + + if (a==redlow) + listener->panelChanged (EvColorToningredlow, redlow->getTextValue()); + else if (a==greenlow) + listener->panelChanged (EvColorToninggreenlow, greenlow->getTextValue()); + else if (a==bluelow) + listener->panelChanged (EvColorToningbluelow, bluelow->getTextValue()); + else if (a==redmed) + listener->panelChanged (EvColorToningredmed, redmed->getTextValue()); + else if (a==greenmed) + listener->panelChanged (EvColorToninggreenmed, greenmed->getTextValue()); + else if (a==bluemed) + listener->panelChanged (EvColorToningbluemed, bluemed->getTextValue()); + else if (a==redhigh) + listener->panelChanged (EvColorToningredhigh, redhigh->getTextValue()); + else if (a==greenhigh) + listener->panelChanged (EvColorToninggreenhigh, greenhigh->getTextValue()); + else if (a==bluehigh) + listener->panelChanged (EvColorToningbluehigh, bluehigh->getTextValue()); + else if (a==balance) + listener->panelChanged (EvColorToningbalance, balance->getTextValue()); + else if (a==satProtectionThreshold) + listener->panelChanged (EvColorToningSatThreshold, a->getTextValue()); + else if (a==saturatedOpacity) + listener->panelChanged (EvColorToningSatProtection, a->getTextValue()); + else if (a==strength) + listener->panelChanged (EvColorToningStrength, a->getTextValue()); +} + +//Two Color changed +void ColorToning::twocolorChanged (bool changedbymethod) { + if (!batchMode) { + if(method->get_active_row_number()==0) { // Lab + if(twocolor->get_active_row_number()==0) { + colorCurveEditorG->show(); // visible + opacityCurveEditorG->show(); // visible + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + } + else if(twocolor->get_active_row_number()==1 || twocolor->get_active_row_number()==3) { + colorCurveEditorG->show(); // visible + opacityCurveEditorG->hide(); + clCurveEditorG->show(); // visible + cl2CurveEditorG->hide(); + irg->hide(); + + } + else if(twocolor->get_active_row_number()==2) { + colorCurveEditorG->show(); // visible + opacityCurveEditorG->hide(); + clCurveEditorG->show(); // visible + cl2CurveEditorG->show(); // visible + irg->show(); + } + } + else if(method->get_active_row_number()==1) { // RGB Sliders + colorCurveEditorG->hide(); + opacityCurveEditorG->hide(); + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + } + else if(method->get_active_row_number()==2) { // RGB Curves + colorCurveEditorG->show(); // visible + opacityCurveEditorG->show(); // visible + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + } + else if(method->get_active_row_number()==3) { // Split LR + colorCurveEditorG->hide(); + opacityCurveEditorG->hide(); + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + } + else if(method->get_active_row_number()==4) { // Split color + colorCurveEditorG->hide(); + opacityCurveEditorG->hide(); + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + } + } + + if (listener && getEnabled() && !changedbymethod) + listener->panelChanged (EvColorToningTwocolor, twocolor->get_active_text ()); +} + +void ColorToning::twoColorChangedByGui() { + twocolorChanged(false); +} + +void ColorToning::methodChanged () { + + if (!batchMode) { + if (method->get_active_row_number()==0) { // Lab + colorSep->show(); + colLabel->hide(); + interLabel->hide(); + colorCurveEditorG->show(); + twocolor->show(); + opacityCurveEditorG->hide(); + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + //neutralCurves->show(); + hlColSat->hide(); + shadowsColSat->hide(); + balance->hide(); +// satLimiterSep->show(); + if(autosat->get_active()) { + saturatedOpacity->set_sensitive(false); + satProtectionThreshold->set_sensitive(false); + satProtectionThreshold->show(); + saturatedOpacity->show(); + } + else { + satProtectionThreshold->show(); + saturatedOpacity->show(); + saturatedOpacity->set_sensitive(true); + satProtectionThreshold->set_sensitive(true); + } + autosat->show(); + p1Frame->show(); + + strength->hide(); + chanMixerBox->hide(); + neutrHBox->hide(); + lumamode->hide(); + //splitSep->hide(); + //satlow->hide(); + //sathigh->hide(); + + twocolorChanged(true); + } + else if (method->get_active_row_number()==1) { // RGB Sliders + colorSep->hide(); + colLabel->hide(); + interLabel->hide(); + colorCurveEditorG->hide(); + twocolor->hide(); + twocolor->set_active (false); + opacityCurveEditorG->hide(); + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + //neutralCurves->hide(); + hlColSat->show(); + shadowsColSat->show(); + balance->show(); +// satLimiterSep->show(); + autosat->show(); + p1Frame->show(); + if(autosat->get_active()) { + saturatedOpacity->set_sensitive(false); + satProtectionThreshold->set_sensitive(false); + satProtectionThreshold->show(); + saturatedOpacity->show(); + } + else { + satProtectionThreshold->show(); + saturatedOpacity->show(); + saturatedOpacity->set_sensitive(true); + satProtectionThreshold->set_sensitive(true); + } + + strength->hide(); + chanMixerBox->hide(); + neutrHBox->hide(); + lumamode->hide(); + + } + else if (method->get_active_row_number()==2) { // RGB Curves + colorSep->hide(); + colLabel->hide(); + interLabel->hide(); + colorCurveEditorG->show(); + twocolor->hide(); + twocolor->set_active (false); + opacityCurveEditorG->show(); + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + //neutralCurves->show(); + hlColSat->hide(); + shadowsColSat->hide(); + balance->hide(); +// satLimiterSep->show(); + p1Frame->show(); + + autosat->show(); + if(autosat->get_active()) { + saturatedOpacity->set_sensitive(false); + satProtectionThreshold->set_sensitive(false); + satProtectionThreshold->show(); + saturatedOpacity->show(); + } + else { + satProtectionThreshold->show(); + saturatedOpacity->show(); + saturatedOpacity->set_sensitive(true); + satProtectionThreshold->set_sensitive(true); + } + strength->hide(); + chanMixerBox->hide(); + neutrHBox->hide(); + lumamode->hide(); + } + else if (method->get_active_row_number()==3) { // Split LR + colorSep->hide(); + colLabel->hide(); + interLabel->hide(); + colorCurveEditorG->hide(); + twocolor->hide(); + twocolor->set_active (false); + opacityCurveEditorG->hide(); + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + //neutralCurves->hide(); + hlColSat->hide(); + shadowsColSat->hide(); + balance->hide(); + p1Frame->hide(); + +// satLimiterSep->hide(); + autosat->hide(); + satProtectionThreshold->hide(); + saturatedOpacity->hide(); + strength->show(); + chanMixerBox->show(); + neutrHBox->show(); + lumamode->show(); + } + else if (method->get_active_row_number()==4) { // Split Color + colorSep->show(); + colLabel->hide(); + interLabel->hide(); + colorCurveEditorG->hide(); + twocolor->hide(); + opacityCurveEditorG->hide(); + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + //neutralCurves->hide(); + hlColSat->show(); + shadowsColSat->show(); + balance->show(); +// satLimiterSep->hide(); + p1Frame->hide(); + + autosat->hide(); + satProtectionThreshold->hide(); + saturatedOpacity->hide(); + strength->show(); + + chanMixerBox->hide(); + neutrHBox->hide(); + lumamode->show(); + } + } + + if (listener && getEnabled()) + listener->panelChanged (EvColorToningMethod, method->get_active_text ()); +} + + +void ColorToning::autoOpenCurve () { + colorShape->openIfNonlinear(); + opacityShape->openIfNonlinear(); + clshape->openIfNonlinear(); + cl2shape->openIfNonlinear(); +} + +void ColorToning::colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller) { + + float R, G, B; + if (callerId == 1) { // ch - main curve + Color::hsv2rgb01(float(valY), 1.0f, 0.5f, R, G, B); + } + else if (callerId == 2) { // Slider 1 background + if (valY > 0.5) + // the hue range + Color::hsv2rgb01(float(valX), 1.0f, 0.5f, R, G, B); + else { + // the strength applied to the current hue + double strength, hue; + float r_, g_, b_; + hlColSat->getValue(strength, hue); + Color::hsv2rgb01(valY*2.f, 1.f, 1.f, r_, g_, b_); + Color::hsv2rgb01(hue/360.f, 1.f, 1.f, R, G, B); + R = r_+(R-r_)*valX; + G = g_+(G-g_)*valX; + B = b_+(B-b_)*valX; + } + } + else if (callerId == 3) { // Slider 2 background + if (valY > 0.5) + // the hue range + Color::hsv2rgb01(float(valX), 1.0f, 0.5f, R, G, B); + else { + // the strength applied to the current hue + double strength, hue; + float r_, g_, b_; + shadowsColSat->getValue(strength, hue); + Color::hsv2rgb01(valY*2.f, 1.f, 1.f, r_, g_, b_); + Color::hsv2rgb01(hue/360.f, 1.f, 1.f, R, G, B); + R = r_+(R-r_)*valX; + G = g_+(G-g_)*valX; + B = b_+(B-b_)*valX; + } + } + caller->ccRed = double(R); + caller->ccGreen = double(G); + caller->ccBlue = double(B); +} + +void ColorToning::curveChanged (CurveEditor* ce) { + + if (listener && getEnabled()) { + if (ce == colorShape) + listener->panelChanged (EvColorToningColor, M("HISTORY_CUSTOMCURVE")); + else if (ce == opacityShape) + listener->panelChanged (EvColorToningOpacity, M("HISTORY_CUSTOMCURVE")); + else if (ce == clshape) + listener->panelChanged (EvColorToningCLCurve, M("HISTORY_CUSTOMCURVE")); + else if (ce == cl2shape) + listener->panelChanged (EvColorToningLLCurve, M("HISTORY_CUSTOMCURVE")); + } +} + +void ColorToning::enabledChanged () { + + if (listener) { + if (get_inconsistent()) + listener->panelChanged (EvColorToningEnabled, M("GENERAL_UNCHANGED")); + else if (getEnabled()) + listener->panelChanged (EvColorToningEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvColorToningEnabled, M("GENERAL_DISABLED")); + } +} + +void ColorToning::autosatChanged () { + + if (batchMode) { + if (autosat->get_inconsistent()) { + autosat->set_inconsistent (false); + autosatConn.block (true); + autosat->set_active (false); + autosatConn.block (false); + } + else if (lastautosat) + autosat->set_inconsistent (true); + + lastautosat = autosat->get_active (); + } + if (listener) { + if (autosat->get_active()) { + if (getEnabled()) + listener->panelChanged (EvColorToningautosat, M("GENERAL_ENABLED")); + saturatedOpacity->set_sensitive(false); + satProtectionThreshold->set_sensitive(false); + } + else { + if (getEnabled()) + listener->panelChanged (EvColorToningautosat, M("GENERAL_DISABLED")); + saturatedOpacity->set_sensitive(true); + satProtectionThreshold->set_sensitive(true); + } + + } +} + +void ColorToning::trimValues (rtengine::procparams::ProcParams* pp) { + + redlow->trimValue(pp->colorToning.redlow); + greenlow->trimValue(pp->colorToning.greenlow); + bluelow->trimValue(pp->colorToning.bluelow); + balance->trimValue(pp->colorToning.balance); + redmed->trimValue(pp->colorToning.redmed); + greenmed->trimValue(pp->colorToning.greenmed); + bluemed->trimValue(pp->colorToning.bluemed); + redhigh->trimValue(pp->colorToning.redhigh); + greenhigh->trimValue(pp->colorToning.greenhigh); + bluehigh->trimValue(pp->colorToning.bluehigh); +} + +void ColorToning::setBatchMode (bool batchMode) +{ + ToolPanel::setBatchMode (batchMode); + method->append_text (M("GENERAL_UNCHANGED")); + twocolor->append_text (M("GENERAL_UNCHANGED")); + hlColSat->showEditedCB (); + shadowsColSat->showEditedCB (); + redlow->showEditedCB (); + greenlow->showEditedCB (); + bluelow->showEditedCB (); + balance->showEditedCB (); + redmed->showEditedCB (); + greenmed->showEditedCB (); + bluemed->showEditedCB (); + redhigh->showEditedCB (); + greenhigh->showEditedCB (); + bluehigh->showEditedCB (); + + colorCurveEditorG->setBatchMode (batchMode); + opacityCurveEditorG->setBatchMode (batchMode); + clCurveEditorG->setBatchMode (batchMode); + cl2CurveEditorG->setBatchMode (batchMode); + +} diff --git a/rtgui/colortoning.h b/rtgui/colortoning.h index b15597d06..7f4a650cf 100644 --- a/rtgui/colortoning.h +++ b/rtgui/colortoning.h @@ -1,107 +1,107 @@ -/* - * This file is part of RawTherapee. - */ -#ifndef _COLORTONING_H_ -#define _COLORTONING_H_ - -#include -#include "adjuster.h" -#include "toolpanel.h" -#include "guiutils.h" -#include "curveeditor.h" -#include "curveeditorgroup.h" -#include "thresholdadjuster.h" -#include "colorprovider.h" - -class ColorToning : public ToolParamBlock, public FoldableToolPanel, public rtengine::AutoColorTonListener,public CurveListener, public ColorProvider, - public ThresholdAdjusterListener, public AdjusterListener { - - protected: - //Gtk::HSeparator* splitSep; - Gtk::HSeparator* satLimiterSep; - Gtk::HSeparator* colorSep; - CurveEditorGroup* colorCurveEditorG; - CurveEditorGroup* opacityCurveEditorG; - CurveEditorGroup* clCurveEditorG; - CurveEditorGroup* cl2CurveEditorG; - FlatCurveEditor* opacityShape; - FlatCurveEditor* colorShape; - DiagonalCurveEditor* clshape; - DiagonalCurveEditor* cl2shape; - Gtk::HBox* ctbox; - Gtk::Frame *p1Frame; - - Gtk::VBox* chanMixerBox; - MyComboBoxText* method; - sigc::connection methodconn; - MyComboBoxText* twocolor; - Adjuster* redlow; - Adjuster* greenlow; - Adjuster* bluelow; - Adjuster* redmed; - Adjuster* greenmed; - Adjuster* bluemed; - Adjuster* redhigh; - Adjuster* greenhigh; - Adjuster* bluehigh; - Adjuster* balance; - Gtk::CheckButton* autosat; - ThresholdAdjuster* shadowsColSat; - ThresholdAdjuster* hlColSat; - Adjuster* satProtectionThreshold; - Adjuster* saturatedOpacity; - Adjuster* strength; - Gtk::Image* itot; - Gtk::Image* iby; - Gtk::Image* irg; - - Gtk::Button* neutral; - //Gtk::Button* neutralCurves; - Gtk::HBox* neutrHBox; - Gtk::HBox* chromaHbox; - Gtk::Label* colLabel; - Gtk::Label* interLabel; - Gtk::Label* chroLabel; - int nextbw; - int nextsatth; - int nextsatpr; - Glib::ustring nextbalcolor; - Glib::ustring balcolor; - bool lasttwocolor; - sigc::connection neutralconn, twocconn; //, neutralcurvesconn; - bool lastautosat; - sigc::connection autosatConn; - - Gtk::CheckButton* lumamode; - bool lastLumamode; - sigc::connection lumamodeConn; - - public: - ColorToning (); - ~ColorToning(); - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - void trimValues (rtengine::procparams::ProcParams* pp); - void adjusterChanged (Adjuster* a, double newval); - void adjusterChanged (ThresholdAdjuster* a, double newBottom, double newTop); - void setAdjusterBehavior (bool splitAdd, bool satThresholdAdd, bool satOpacityAdd, bool strprotectAdd, bool balanceAdd); - void neutral_pressed (); - //void neutralCurves_pressed (); - void autoColorTonChanged (int bwct, int satthres, int satprot); - bool CTComp_ (); - - void enabledChanged (); - void curveChanged (CurveEditor* ce); - void autosatChanged (); - void autoOpenCurve (); - void methodChanged (); - void twocolorChanged (bool changedbymethod); - void twoColorChangedByGui (); - void lumamodeChanged (); - - void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller); -}; - -#endif +/* + * This file is part of RawTherapee. + */ +#ifndef _COLORTONING_H_ +#define _COLORTONING_H_ + +#include +#include "adjuster.h" +#include "toolpanel.h" +#include "guiutils.h" +#include "curveeditor.h" +#include "curveeditorgroup.h" +#include "thresholdadjuster.h" +#include "colorprovider.h" + +class ColorToning : public ToolParamBlock, public FoldableToolPanel, public rtengine::AutoColorTonListener,public CurveListener, public ColorProvider, + public ThresholdAdjusterListener, public AdjusterListener { + + protected: + //Gtk::HSeparator* splitSep; + Gtk::HSeparator* satLimiterSep; + Gtk::HSeparator* colorSep; + CurveEditorGroup* colorCurveEditorG; + CurveEditorGroup* opacityCurveEditorG; + CurveEditorGroup* clCurveEditorG; + CurveEditorGroup* cl2CurveEditorG; + FlatCurveEditor* opacityShape; + FlatCurveEditor* colorShape; + DiagonalCurveEditor* clshape; + DiagonalCurveEditor* cl2shape; + Gtk::HBox* ctbox; + Gtk::Frame *p1Frame; + + Gtk::VBox* chanMixerBox; + MyComboBoxText* method; + sigc::connection methodconn; + MyComboBoxText* twocolor; + Adjuster* redlow; + Adjuster* greenlow; + Adjuster* bluelow; + Adjuster* redmed; + Adjuster* greenmed; + Adjuster* bluemed; + Adjuster* redhigh; + Adjuster* greenhigh; + Adjuster* bluehigh; + Adjuster* balance; + Gtk::CheckButton* autosat; + ThresholdAdjuster* shadowsColSat; + ThresholdAdjuster* hlColSat; + Adjuster* satProtectionThreshold; + Adjuster* saturatedOpacity; + Adjuster* strength; + Gtk::Image* itot; + Gtk::Image* iby; + Gtk::Image* irg; + + Gtk::Button* neutral; + //Gtk::Button* neutralCurves; + Gtk::HBox* neutrHBox; + Gtk::HBox* chromaHbox; + Gtk::Label* colLabel; + Gtk::Label* interLabel; + Gtk::Label* chroLabel; + int nextbw; + int nextsatth; + int nextsatpr; + Glib::ustring nextbalcolor; + Glib::ustring balcolor; + bool lasttwocolor; + sigc::connection neutralconn, twocconn; //, neutralcurvesconn; + bool lastautosat; + sigc::connection autosatConn; + + Gtk::CheckButton* lumamode; + bool lastLumamode; + sigc::connection lumamodeConn; + + public: + ColorToning (); + ~ColorToning(); + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void trimValues (rtengine::procparams::ProcParams* pp); + void adjusterChanged (Adjuster* a, double newval); + void adjusterChanged (ThresholdAdjuster* a, double newBottom, double newTop); + void setAdjusterBehavior (bool splitAdd, bool satThresholdAdd, bool satOpacityAdd, bool strprotectAdd, bool balanceAdd); + void neutral_pressed (); + //void neutralCurves_pressed (); + void autoColorTonChanged (int bwct, int satthres, int satprot); + bool CTComp_ (); + + void enabledChanged (); + void curveChanged (CurveEditor* ce); + void autosatChanged (); + void autoOpenCurve (); + void methodChanged (); + void twocolorChanged (bool changedbymethod); + void twoColorChangedByGui (); + void lumamodeChanged (); + + void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller); +}; + +#endif diff --git a/rtgui/coord.h b/rtgui/coord.h index 91fc40562..8b40fa689 100644 --- a/rtgui/coord.h +++ b/rtgui/coord.h @@ -1,163 +1,163 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _COORD_H_ -#define _COORD_H_ - -class PolarCoord; - -// Do not confuse with rtengine::Coord2D, Coord is for the GUI -class Coord { -public: - int x; - int y; - - Coord() : x(-1), y(-1) {} - Coord(int x, int y) : x(x), y(y) {} - - void set (int x, int y) { - this->x = x; - this->y = y; - } - - void setFromPolar(PolarCoord polar); - - /// @brief Clip the coord to stay in the width x height bounds - /// @return true if the x or y coordinate has changed - bool clip(int width, int height) { - int trimmedX = rtengine::LIM(x, 0, width); - int trimmedY = rtengine::LIM(y, 0, height); - bool retval = trimmedX!=x || trimmedY!=y; - x = trimmedX; - y = trimmedY; - return retval; - } - - void operator+=(const Coord & rhs) { - x += rhs.x; - y += rhs.y; - } - void operator-=(const Coord & rhs) { - x -= rhs.x; - y -= rhs.y; - } - void operator*=(double scale) { - x *= scale; - y *= scale; - } - Coord operator+(Coord & rhs) { - Coord result(x+rhs.x, y+rhs.y); - return result; - } - Coord operator-(Coord & rhs) { - Coord result(x-rhs.x, y-rhs.y); - return result; - } - Coord operator*(double scale) { - Coord result(x*scale, y*scale); - return result; - } -}; - -class PolarCoord { -public: - double radius; - double angle; // degree - - PolarCoord() : radius(1.), angle(0.) {} - PolarCoord(double radius, double angle) : radius(radius), angle(angle) {} - - void set (double radius, double angle) { - this->radius = radius; - this->angle = angle; - } - - void setFromCartesian(Coord start, Coord end) { - Coord delta(end.x-start.x, end.y-start.y); - setFromCartesian(delta); - } - - void setFromCartesian(Coord delta) { - if (!delta.x && !delta.y) { - // null vector, we set to a default value - radius = 1.; - angle = 0.; - return; - } - double x_ = double(delta.x); - double y_ = double(delta.y); - radius = sqrt(x_*x_+y_*y_); - if (delta.x>0.) { - if (delta.y>=0.) - angle = atan(y_/x_)/(2*M_PI)*360.; - else if (delta.y<0.) - angle = (atan(y_/x_)+2*M_PI)/(2*M_PI)*360.; - } - else if (delta.x<0.) - angle = (atan(y_/x_)+M_PI)/(2*M_PI)*360.; - else if (delta.x==0.) { - if (delta.y>0.) - angle = 90.; - else - angle = 270.; - } - } - - void operator+=(const PolarCoord & rhs) { - Coord thisCoord, rhsCoord; - thisCoord.setFromPolar(*this); - rhsCoord.setFromPolar(rhs); - thisCoord += rhsCoord; - setFromCartesian(thisCoord); - } - void operator-=(const PolarCoord & rhs) { - Coord thisCoord, rhsCoord; - thisCoord.setFromPolar(*this); - rhsCoord.setFromPolar(rhs); - thisCoord -= rhsCoord; - setFromCartesian(thisCoord); - } - void operator*=(double scale) { - radius *= scale; - } - PolarCoord operator+(PolarCoord & rhs) { - Coord thisCoord, rhsCoord; - thisCoord.setFromPolar(*this); - rhsCoord.setFromPolar(rhs); - thisCoord += rhsCoord; - PolarCoord result; - result.setFromCartesian(thisCoord); - return result; - } - PolarCoord operator-(PolarCoord & rhs) { - Coord thisCoord, rhsCoord; - thisCoord.setFromPolar(*this); - rhsCoord.setFromPolar(rhs); - thisCoord -= rhsCoord; - PolarCoord result; - result.setFromCartesian(thisCoord); - return result; - } - Coord operator*(double scale) { - Coord result(radius*scale, angle); - return result; - } - -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _COORD_H_ +#define _COORD_H_ + +class PolarCoord; + +// Do not confuse with rtengine::Coord2D, Coord is for the GUI +class Coord { +public: + int x; + int y; + + Coord() : x(-1), y(-1) {} + Coord(int x, int y) : x(x), y(y) {} + + void set (int x, int y) { + this->x = x; + this->y = y; + } + + void setFromPolar(PolarCoord polar); + + /// @brief Clip the coord to stay in the width x height bounds + /// @return true if the x or y coordinate has changed + bool clip(int width, int height) { + int trimmedX = rtengine::LIM(x, 0, width); + int trimmedY = rtengine::LIM(y, 0, height); + bool retval = trimmedX!=x || trimmedY!=y; + x = trimmedX; + y = trimmedY; + return retval; + } + + void operator+=(const Coord & rhs) { + x += rhs.x; + y += rhs.y; + } + void operator-=(const Coord & rhs) { + x -= rhs.x; + y -= rhs.y; + } + void operator*=(double scale) { + x *= scale; + y *= scale; + } + Coord operator+(Coord & rhs) { + Coord result(x+rhs.x, y+rhs.y); + return result; + } + Coord operator-(Coord & rhs) { + Coord result(x-rhs.x, y-rhs.y); + return result; + } + Coord operator*(double scale) { + Coord result(x*scale, y*scale); + return result; + } +}; + +class PolarCoord { +public: + double radius; + double angle; // degree + + PolarCoord() : radius(1.), angle(0.) {} + PolarCoord(double radius, double angle) : radius(radius), angle(angle) {} + + void set (double radius, double angle) { + this->radius = radius; + this->angle = angle; + } + + void setFromCartesian(Coord start, Coord end) { + Coord delta(end.x-start.x, end.y-start.y); + setFromCartesian(delta); + } + + void setFromCartesian(Coord delta) { + if (!delta.x && !delta.y) { + // null vector, we set to a default value + radius = 1.; + angle = 0.; + return; + } + double x_ = double(delta.x); + double y_ = double(delta.y); + radius = sqrt(x_*x_+y_*y_); + if (delta.x>0.) { + if (delta.y>=0.) + angle = atan(y_/x_)/(2*M_PI)*360.; + else if (delta.y<0.) + angle = (atan(y_/x_)+2*M_PI)/(2*M_PI)*360.; + } + else if (delta.x<0.) + angle = (atan(y_/x_)+M_PI)/(2*M_PI)*360.; + else if (delta.x==0.) { + if (delta.y>0.) + angle = 90.; + else + angle = 270.; + } + } + + void operator+=(const PolarCoord & rhs) { + Coord thisCoord, rhsCoord; + thisCoord.setFromPolar(*this); + rhsCoord.setFromPolar(rhs); + thisCoord += rhsCoord; + setFromCartesian(thisCoord); + } + void operator-=(const PolarCoord & rhs) { + Coord thisCoord, rhsCoord; + thisCoord.setFromPolar(*this); + rhsCoord.setFromPolar(rhs); + thisCoord -= rhsCoord; + setFromCartesian(thisCoord); + } + void operator*=(double scale) { + radius *= scale; + } + PolarCoord operator+(PolarCoord & rhs) { + Coord thisCoord, rhsCoord; + thisCoord.setFromPolar(*this); + rhsCoord.setFromPolar(rhs); + thisCoord += rhsCoord; + PolarCoord result; + result.setFromCartesian(thisCoord); + return result; + } + PolarCoord operator-(PolarCoord & rhs) { + Coord thisCoord, rhsCoord; + thisCoord.setFromPolar(*this); + rhsCoord.setFromPolar(rhs); + thisCoord -= rhsCoord; + PolarCoord result; + result.setFromCartesian(thisCoord); + return result; + } + Coord operator*(double scale) { + Coord result(radius*scale, angle); + return result; + } + +}; + +#endif diff --git a/rtgui/coordinateadjuster.cc b/rtgui/coordinateadjuster.cc index 35bbe51e0..91303ec46 100644 --- a/rtgui/coordinateadjuster.cc +++ b/rtgui/coordinateadjuster.cc @@ -1,198 +1,198 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include "coordinateadjuster.h" -#include "multilangmgr.h" -#include -#include "curveeditorgroup.h" - -Axis::Axis() - : label(""), decimal(5), increment(0.001), pageIncrement(0.01), rangeLowerBound(0.), rangeUpperBound(1.) -{} - -Axis::Axis(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin=0.0, double valMax=1.0) - : label(label), decimal(decimal), increment(increment), pageIncrement(pageIncrement), rangeLowerBound(valMin), rangeUpperBound(valMax) -{} - -void Axis::setValues(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax) { - this->label = label; - this->decimal = decimal; - this->increment = increment; - this->pageIncrement = pageIncrement; - this->rangeLowerBound = valMin; - this->rangeUpperBound = valMax; -} - -CoordinateAdjuster::AxisAdjuster::AxisAdjuster(CoordinateAdjuster *parent, const Axis *axis, char index) : idx(index), parent(parent) { - label = Gtk::manage( new Gtk::Label(axis->label) ); - spinButton = Gtk::manage( new Gtk::SpinButton() ); - - label = Gtk::manage (new Gtk::Label(axis->label)); - //label->set_alignment(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); - - spinButton = Gtk::manage (new Gtk::SpinButton()); - spinButton->set_name("AxisAdjuster"); - spinButton->set_digits(axis->decimal); - spinButton->set_increments(axis->increment, axis->pageIncrement); - spinButton->set_range(axis->rangeLowerBound, axis->rangeUpperBound); - spinButton->set_sensitive(false); - spinButtonConn = spinButton->signal_value_changed().connect( sigc::mem_fun(*this, &CoordinateAdjuster::AxisAdjuster::valueChanged) ); - //spinButton->signal_key_press_event().connect( sigc::mem_fun(*this, &CoordinateAdjuster::AxisAdjuster::keyPressed) ); -} - -void CoordinateAdjuster::AxisAdjuster::updateGUI(const Axis &axis) { - label->set_text(axis.label); - spinButton->set_digits(axis.decimal); - spinButton->set_increments(axis.increment, axis.pageIncrement); - spinButton->set_range(axis.rangeLowerBound, axis.rangeUpperBound); - spinButton->set_sensitive(false); - rangeLowerBound = axis.rangeLowerBound; - rangeUpperBound = axis.rangeUpperBound; -} - -void CoordinateAdjuster::AxisAdjuster::setValue(double newValue) { - float range = rangeUpperBound-rangeLowerBound; - spinButtonConn.block(true); - spinButton->set_value(newValue*range+rangeLowerBound); - spinButtonConn.block(false); -} - -void CoordinateAdjuster::AxisAdjuster::valueChanged() { - float range = rangeUpperBound-rangeLowerBound; - parent->updatePos(idx, (spinButton->get_value()-rangeLowerBound)/range); -} - -CoordinateAdjuster::CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent, const std::vector &axis) - : status(CA_STATUS_IDLE), parent(parent), coordinateProvider(provider) -{ - provider->setListener(this); - createWidgets(axis); -} - -CoordinateAdjuster::CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent) - : status(CA_STATUS_IDLE), parent(parent), coordinateProvider(provider) -{ - std::vector defaultAxis; - Axis X(M("CURVEEDITOR_AXIS_IN"), 3, 0.1, 1., 0., 100.); - Axis Y(M("CURVEEDITOR_AXIS_OUT"), 3, 0.1, 1., 0., 100.); - defaultAxis.push_back(X); - defaultAxis.push_back(Y); - - provider->setListener(this); - createWidgets(defaultAxis); -} - -void CoordinateAdjuster::createWidgets(const std::vector &axis) { - unsigned int count = axis.size(); - if (!count) { - printf("CoordinateAdjuster - Error: the Axis list is empty!\n"); - return; - } - assert (count <= 4); - - axisAdjusters.resize(axis.size()); - - set_spacing(3); - - AxisAdjuster *currAdjuster = NULL; - - for (unsigned int i=0; irangeLowerBound = currAxis->rangeLowerBound; - currAdjuster->rangeUpperBound = currAxis->rangeUpperBound; - - pack_start(*(currAdjuster->label), Gtk::PACK_SHRINK, 0); - pack_start(*(currAdjuster->spinButton), Gtk::PACK_SHRINK, 0); - } -} - -void CoordinateAdjuster::updatePos(char index, double value) { - coordinateProvider->setPos(value, index); -} - -void CoordinateAdjuster::setAxis(const std::vector &axis) { - assert (axis.size() == axisAdjusters.size()); - for (size_t i = 0; iupdateGUI(axis.at(i)); - } -} - -void CoordinateAdjuster::setPos(std::vector &pos) { - if (is_visible()) { - for (size_t i=0; isetValue(pos.at(i)); - } - } -} - -void CoordinateAdjuster::startNumericalAdjustment(const std::vector &newBoundaries) { - for (size_t i=0; ispinButton; - currSpinButton->set_sensitive(true); - float range = axisAdjusters.at(i)->rangeUpperBound-axisAdjusters.at(i)->rangeLowerBound; - currSpinButton->set_range(newBoundaries.at(i).minVal*range+axisAdjusters.at(i)->rangeLowerBound, newBoundaries.at(i).maxVal*range+axisAdjusters.at(i)->rangeUpperBound); - } - axisAdjusters.at(0)->spinButton->grab_focus(); - status = CA_STATUS_EDITING; -} - -void CoordinateAdjuster::switchAdjustedPoint(std::vector &pos, const std::vector &newBoundaries) { - if (status != CA_STATUS_EDITING) - return; - - for (size_t i=0; ispinButtonConn.block(true); - - // To avoid trimmed values, we have to... - - // ...enlarge range to the maximum - currAxis->spinButton->set_range(axisAdjusters.at(i)->rangeLowerBound, axisAdjusters.at(i)->rangeUpperBound); - - // ...set the new value - currAxis->setValue(pos.at(i)); - - // ...narrow the range to the new interval - float range = axisAdjusters.at(i)->rangeUpperBound-axisAdjusters.at(i)->rangeLowerBound; - currAxis->spinButton->set_range(newBoundaries.at(i).minVal*range+axisAdjusters.at(i)->rangeLowerBound, newBoundaries.at(i).maxVal*range+axisAdjusters.at(i)->rangeUpperBound); - - // enable events - currAxis->spinButtonConn.block(false); - } - axisAdjusters.at(0)->spinButton->grab_focus(); - status = CA_STATUS_EDITING; -} - -void CoordinateAdjuster::showMe(CoordinateProvider *provider) { - parent->showCoordinateAdjuster(provider); -} - -void CoordinateAdjuster::stopNumericalAdjustment() { - for (size_t i=0; ispinButtonConn.block(true); - axisAdjusters.at(i)->spinButton->set_sensitive(false); - axisAdjusters.at(i)->spinButton->set_range(axisAdjusters.at(i)->rangeLowerBound, axisAdjusters.at(i)->rangeUpperBound); - axisAdjusters.at(i)->spinButtonConn.block(false); - } - status = CA_STATUS_IDLE; -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "coordinateadjuster.h" +#include "multilangmgr.h" +#include +#include "curveeditorgroup.h" + +Axis::Axis() + : label(""), decimal(5), increment(0.001), pageIncrement(0.01), rangeLowerBound(0.), rangeUpperBound(1.) +{} + +Axis::Axis(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin=0.0, double valMax=1.0) + : label(label), decimal(decimal), increment(increment), pageIncrement(pageIncrement), rangeLowerBound(valMin), rangeUpperBound(valMax) +{} + +void Axis::setValues(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax) { + this->label = label; + this->decimal = decimal; + this->increment = increment; + this->pageIncrement = pageIncrement; + this->rangeLowerBound = valMin; + this->rangeUpperBound = valMax; +} + +CoordinateAdjuster::AxisAdjuster::AxisAdjuster(CoordinateAdjuster *parent, const Axis *axis, char index) : idx(index), parent(parent) { + label = Gtk::manage( new Gtk::Label(axis->label) ); + spinButton = Gtk::manage( new Gtk::SpinButton() ); + + label = Gtk::manage (new Gtk::Label(axis->label)); + //label->set_alignment(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + + spinButton = Gtk::manage (new Gtk::SpinButton()); + spinButton->set_name("AxisAdjuster"); + spinButton->set_digits(axis->decimal); + spinButton->set_increments(axis->increment, axis->pageIncrement); + spinButton->set_range(axis->rangeLowerBound, axis->rangeUpperBound); + spinButton->set_sensitive(false); + spinButtonConn = spinButton->signal_value_changed().connect( sigc::mem_fun(*this, &CoordinateAdjuster::AxisAdjuster::valueChanged) ); + //spinButton->signal_key_press_event().connect( sigc::mem_fun(*this, &CoordinateAdjuster::AxisAdjuster::keyPressed) ); +} + +void CoordinateAdjuster::AxisAdjuster::updateGUI(const Axis &axis) { + label->set_text(axis.label); + spinButton->set_digits(axis.decimal); + spinButton->set_increments(axis.increment, axis.pageIncrement); + spinButton->set_range(axis.rangeLowerBound, axis.rangeUpperBound); + spinButton->set_sensitive(false); + rangeLowerBound = axis.rangeLowerBound; + rangeUpperBound = axis.rangeUpperBound; +} + +void CoordinateAdjuster::AxisAdjuster::setValue(double newValue) { + float range = rangeUpperBound-rangeLowerBound; + spinButtonConn.block(true); + spinButton->set_value(newValue*range+rangeLowerBound); + spinButtonConn.block(false); +} + +void CoordinateAdjuster::AxisAdjuster::valueChanged() { + float range = rangeUpperBound-rangeLowerBound; + parent->updatePos(idx, (spinButton->get_value()-rangeLowerBound)/range); +} + +CoordinateAdjuster::CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent, const std::vector &axis) + : status(CA_STATUS_IDLE), parent(parent), coordinateProvider(provider) +{ + provider->setListener(this); + createWidgets(axis); +} + +CoordinateAdjuster::CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent) + : status(CA_STATUS_IDLE), parent(parent), coordinateProvider(provider) +{ + std::vector defaultAxis; + Axis X(M("CURVEEDITOR_AXIS_IN"), 3, 0.1, 1., 0., 100.); + Axis Y(M("CURVEEDITOR_AXIS_OUT"), 3, 0.1, 1., 0., 100.); + defaultAxis.push_back(X); + defaultAxis.push_back(Y); + + provider->setListener(this); + createWidgets(defaultAxis); +} + +void CoordinateAdjuster::createWidgets(const std::vector &axis) { + unsigned int count = axis.size(); + if (!count) { + printf("CoordinateAdjuster - Error: the Axis list is empty!\n"); + return; + } + assert (count <= 4); + + axisAdjusters.resize(axis.size()); + + set_spacing(3); + + AxisAdjuster *currAdjuster = NULL; + + for (unsigned int i=0; irangeLowerBound = currAxis->rangeLowerBound; + currAdjuster->rangeUpperBound = currAxis->rangeUpperBound; + + pack_start(*(currAdjuster->label), Gtk::PACK_SHRINK, 0); + pack_start(*(currAdjuster->spinButton), Gtk::PACK_SHRINK, 0); + } +} + +void CoordinateAdjuster::updatePos(char index, double value) { + coordinateProvider->setPos(value, index); +} + +void CoordinateAdjuster::setAxis(const std::vector &axis) { + assert (axis.size() == axisAdjusters.size()); + for (size_t i = 0; iupdateGUI(axis.at(i)); + } +} + +void CoordinateAdjuster::setPos(std::vector &pos) { + if (is_visible()) { + for (size_t i=0; isetValue(pos.at(i)); + } + } +} + +void CoordinateAdjuster::startNumericalAdjustment(const std::vector &newBoundaries) { + for (size_t i=0; ispinButton; + currSpinButton->set_sensitive(true); + float range = axisAdjusters.at(i)->rangeUpperBound-axisAdjusters.at(i)->rangeLowerBound; + currSpinButton->set_range(newBoundaries.at(i).minVal*range+axisAdjusters.at(i)->rangeLowerBound, newBoundaries.at(i).maxVal*range+axisAdjusters.at(i)->rangeUpperBound); + } + axisAdjusters.at(0)->spinButton->grab_focus(); + status = CA_STATUS_EDITING; +} + +void CoordinateAdjuster::switchAdjustedPoint(std::vector &pos, const std::vector &newBoundaries) { + if (status != CA_STATUS_EDITING) + return; + + for (size_t i=0; ispinButtonConn.block(true); + + // To avoid trimmed values, we have to... + + // ...enlarge range to the maximum + currAxis->spinButton->set_range(axisAdjusters.at(i)->rangeLowerBound, axisAdjusters.at(i)->rangeUpperBound); + + // ...set the new value + currAxis->setValue(pos.at(i)); + + // ...narrow the range to the new interval + float range = axisAdjusters.at(i)->rangeUpperBound-axisAdjusters.at(i)->rangeLowerBound; + currAxis->spinButton->set_range(newBoundaries.at(i).minVal*range+axisAdjusters.at(i)->rangeLowerBound, newBoundaries.at(i).maxVal*range+axisAdjusters.at(i)->rangeUpperBound); + + // enable events + currAxis->spinButtonConn.block(false); + } + axisAdjusters.at(0)->spinButton->grab_focus(); + status = CA_STATUS_EDITING; +} + +void CoordinateAdjuster::showMe(CoordinateProvider *provider) { + parent->showCoordinateAdjuster(provider); +} + +void CoordinateAdjuster::stopNumericalAdjustment() { + for (size_t i=0; ispinButtonConn.block(true); + axisAdjusters.at(i)->spinButton->set_sensitive(false); + axisAdjusters.at(i)->spinButton->set_range(axisAdjusters.at(i)->rangeLowerBound, axisAdjusters.at(i)->rangeUpperBound); + axisAdjusters.at(i)->spinButtonConn.block(false); + } + status = CA_STATUS_IDLE; +} diff --git a/rtgui/coordinateadjuster.h b/rtgui/coordinateadjuster.h index 3c4dbc38f..de85b6623 100644 --- a/rtgui/coordinateadjuster.h +++ b/rtgui/coordinateadjuster.h @@ -1,157 +1,157 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _COORDINATEADJUSTER_ -#define _COORDINATEADJUSTER_ - -#include - -class CurveEditorSubGroup; - -class Axis { -public: - Glib::ustring label; - unsigned int decimal; - double increment; - double pageIncrement; - double rangeLowerBound; - double rangeUpperBound; - - Axis(); - Axis(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax); - void setValues(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax); -}; - -class CoordinateAdjuster; -/** - * @brief Object that will emit NewCoordinates events - */ -class CoordinateProvider { -protected: - CoordinateAdjuster *coordinateAdjuster; -public: - CoordinateProvider() : coordinateAdjuster(NULL) {} - virtual ~CoordinateProvider() {} - void setListener(CoordinateAdjuster *adjuster) { coordinateAdjuster = adjuster; } - - /** @brief Update the position of the edited point ; will trigger events - * - * @param pos New position - * @param chanIdx Chanel index as given in the std::vector upon instantiation - */ - virtual void setPos(double pos, int chanIdx)=0; - virtual void stopNumericalAdjustment()=0; -}; - -/** - * @brief Widget that displays spin buttons to adjust coordinates - * - * You can set up to 4 axis that will be displayed on a single line, so keep the labels short! - * - * The position of the Axis in the vector will be used in the communication between the Adjuster and the Provider to identify the Axis - */ -class CoordinateAdjuster : public Gtk::HBox { - -public: - //-------------------------------- AxisAdjuster ------------------- - class AxisAdjuster { - private: - char idx; - public: - CoordinateAdjuster *parent; - Gtk::Label *label; - Gtk::SpinButton *spinButton; - sigc::connection spinButtonConn; - float rangeLowerBound; - float rangeUpperBound; - - AxisAdjuster(CoordinateAdjuster *parent, const Axis *axis, char index); - - // used to update the AxisAdjuster's parameters - void updateGUI(const Axis &axis); - // useed to update the displayed value - void setValue(double newValue); - //bool keyPressed(GdkEventKey* event); - void valueChanged(); - }; - //---------------------------------------------------------------- - - //-------------------------------- Boundaries ------------------- - class Boundaries { - public: - double minVal; - double maxVal; - }; - //--------------------------------------------------------------- - -private: - typedef enum { - CA_STATUS_IDLE, - CA_STATUS_EDITING, - CA_STATUS_END_EDITING - } Status; - - std::vector axisAdjusters; - Status status; - CurveEditorSubGroup *parent; - - void createWidgets(const std::vector &axis); - -protected: - - friend class AxisAdjuster; - - CoordinateProvider *coordinateProvider; - - void updatePos(char index, double value); - - -public: - - /// Basic X/Y adjuster, in the [0-1] range - CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent); - /// For more complex adjuster - CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent, const std::vector &axis); - - virtual ~CoordinateAdjuster() {} - - // Update the Axis list, e.g. on Curve change, but MUST have the same axis count - void setAxis(const std::vector &axis); - - /** @brief Update the numbers in the spin buttons ; doesn't trigger any event - * - * @param pos Vector that gives the values of each channels - */ - void setPos(std::vector &pos); - - /// Start the adjustment session (enable the widget) - void startNumericalAdjustment(const std::vector &newBoundaries); - - /// Edit another point - void switchAdjustedPoint(std::vector &pos, const std::vector &newBoundaries); - - /// Trigger the event to show the CoordinateAdjuster - void showMe(CoordinateProvider *provider); - - /// Stop the adjustment session (disable the widget, i.e. you won't be able to edit the values) - void stopNumericalAdjustment(); - -}; - - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _COORDINATEADJUSTER_ +#define _COORDINATEADJUSTER_ + +#include + +class CurveEditorSubGroup; + +class Axis { +public: + Glib::ustring label; + unsigned int decimal; + double increment; + double pageIncrement; + double rangeLowerBound; + double rangeUpperBound; + + Axis(); + Axis(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax); + void setValues(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax); +}; + +class CoordinateAdjuster; +/** + * @brief Object that will emit NewCoordinates events + */ +class CoordinateProvider { +protected: + CoordinateAdjuster *coordinateAdjuster; +public: + CoordinateProvider() : coordinateAdjuster(NULL) {} + virtual ~CoordinateProvider() {} + void setListener(CoordinateAdjuster *adjuster) { coordinateAdjuster = adjuster; } + + /** @brief Update the position of the edited point ; will trigger events + * + * @param pos New position + * @param chanIdx Chanel index as given in the std::vector upon instantiation + */ + virtual void setPos(double pos, int chanIdx)=0; + virtual void stopNumericalAdjustment()=0; +}; + +/** + * @brief Widget that displays spin buttons to adjust coordinates + * + * You can set up to 4 axis that will be displayed on a single line, so keep the labels short! + * + * The position of the Axis in the vector will be used in the communication between the Adjuster and the Provider to identify the Axis + */ +class CoordinateAdjuster : public Gtk::HBox { + +public: + //-------------------------------- AxisAdjuster ------------------- + class AxisAdjuster { + private: + char idx; + public: + CoordinateAdjuster *parent; + Gtk::Label *label; + Gtk::SpinButton *spinButton; + sigc::connection spinButtonConn; + float rangeLowerBound; + float rangeUpperBound; + + AxisAdjuster(CoordinateAdjuster *parent, const Axis *axis, char index); + + // used to update the AxisAdjuster's parameters + void updateGUI(const Axis &axis); + // useed to update the displayed value + void setValue(double newValue); + //bool keyPressed(GdkEventKey* event); + void valueChanged(); + }; + //---------------------------------------------------------------- + + //-------------------------------- Boundaries ------------------- + class Boundaries { + public: + double minVal; + double maxVal; + }; + //--------------------------------------------------------------- + +private: + typedef enum { + CA_STATUS_IDLE, + CA_STATUS_EDITING, + CA_STATUS_END_EDITING + } Status; + + std::vector axisAdjusters; + Status status; + CurveEditorSubGroup *parent; + + void createWidgets(const std::vector &axis); + +protected: + + friend class AxisAdjuster; + + CoordinateProvider *coordinateProvider; + + void updatePos(char index, double value); + + +public: + + /// Basic X/Y adjuster, in the [0-1] range + CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent); + /// For more complex adjuster + CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent, const std::vector &axis); + + virtual ~CoordinateAdjuster() {} + + // Update the Axis list, e.g. on Curve change, but MUST have the same axis count + void setAxis(const std::vector &axis); + + /** @brief Update the numbers in the spin buttons ; doesn't trigger any event + * + * @param pos Vector that gives the values of each channels + */ + void setPos(std::vector &pos); + + /// Start the adjustment session (enable the widget) + void startNumericalAdjustment(const std::vector &newBoundaries); + + /// Edit another point + void switchAdjustedPoint(std::vector &pos, const std::vector &newBoundaries); + + /// Trigger the event to show the CoordinateAdjuster + void showMe(CoordinateProvider *provider); + + /// Stop the adjustment session (disable the widget, i.e. you won't be able to edit the values) + void stopNumericalAdjustment(); + +}; + + +#endif diff --git a/rtgui/curveeditor.h b/rtgui/curveeditor.h index 45ef69cc3..aafe3a1a9 100644 --- a/rtgui/curveeditor.h +++ b/rtgui/curveeditor.h @@ -1,196 +1,196 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _CURVEEDITOR_ -#define _CURVEEDITOR_ - -#include "popuptogglebutton.h" -#include "../rtengine/LUT.h" -#include "coloredbar.h" -#include "edit.h" -#include "mydiagonalcurve.h" -#include "myflatcurve.h" - -class CurveEditorGroup; -class CurveEditorSubGroup; - - -/* - *********************** Curve Editor *********************** - */ - - -/* - * This class is an interface between RT and the curve editor group ; it handles the methods - * related to a specific curve. It is created by CurveEditorGroup::addCurve - */ -class CurveEditor : public EditSubscriber { - - friend class CurveEditorGroup; - friend class CurveEditorSubGroup; - friend class DiagonalCurveEditorSubGroup; - friend class FlatCurveEditorSubGroup; - friend class DiagonalCurveEditor; - friend class FlatCurveEditor; - - protected: - - /* - * The curve editor contains only one widget (the curve type button) to receive the signals - * but it's co-handled by the CurveEditorGroup too - */ - - PopUpToggleButton* curveType; - LUTu histogram; // histogram values - bool bgHistValid; - - bool remoteDrag; - - int selected; - - CurveEditorGroup* group; - CurveEditorSubGroup* subGroup; - Gtk::Widget* relatedWidget; - - std::vector tempCurve; - sigc::connection typeconn; - - ColorProvider* bottomBarCP; - ColorProvider* leftBarCP; - ColorProvider* curveCP; - int bottomBarCId; - int leftBarCId; - int curveCId; - std::vector bottomBarBgGradient; - std::vector leftBarBgGradient; - - sigc::signal sig_curvegraph_enter; - sigc::signal sig_curvegraph_leave; - sigc::signal sig_curvepoint_click; - sigc::signal sig_curvepoint_release; - - public: - - CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup); - virtual ~CurveEditor (); - void typeSelectionChanged (int n); - void curveTypeToggled(); - bool isUnChanged (); - void setUnChanged (bool uc); - void updateBackgroundHistogram (LUTu & hist); - - void setLeftBarColorProvider(ColorProvider* cp, int callerId); - void setBottomBarColorProvider(ColorProvider* cp, int callerId); - void setCurveColorProvider(ColorProvider* cp, int callerId); - void setBottomBarBgGradient (const std::vector &milestones); - void setLeftBarBgGradient (const std::vector &milestones); - ColorProvider* getLeftBarColorProvider(); - ColorProvider* getBottomBarColorProvider(); - ColorProvider* getCurveColorProvider(); - int getLeftBarCallerId(); - int getBottomBarCallerId(); - int getCurveCallerId(); - std::vector getBottomBarBgGradient () const; - std::vector getLeftBarBgGradient () const; - - void refresh (); // refresh the display of the CurveEditor (e.g. when a ColoredBar has been changed from the outside) - bool openIfNonlinear(); // Open up the curve if it has modifications and it's not already opened - - void setCurve (const std::vector& p); - virtual void setIdentityValue (const double iValue=0.5) {}; - virtual double getIdentityValue () { return 0.5; }; - virtual std::vector getCurve () = 0; - bool reset(); - void setTooltip(Glib::ustring ttip); - - sigc::signal signal_curvegraph_enter(); - sigc::signal signal_curvegraph_leave(); - sigc::signal signal_curvepoint_click(); - sigc::signal signal_curvepoint_release(); - - void switchOffEditMode (); - bool mouseOver(int modifierKey); - bool button1Pressed(int modifierKey); - bool button1Released(); - bool drag(int modifierKey); - CursorShape getCursor(int objectID); - - -}; - - -/* - ******************** Diagonal Curve Editor ******************** - */ - - -class DiagonalCurveEditor : public CurveEditor { - - friend class DiagonalCurveEditorSubGroup; - - protected: - // reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value - std::vector customCurveEd; - std::vector customResetCurve; - std::vector paramCurveEd; - std::vector paramResetCurve; - std::vector NURBSCurveEd; - std::vector NURBSResetCurve; - Glib::ustring rangeLabels[4]; - double rangeMilestones[3]; - - public: - DiagonalCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup); - std::vector getCurve (); - void setRangeLabels(Glib::ustring r1, Glib::ustring r2, Glib::ustring r3, Glib::ustring r4); - void getRangeLabels(Glib::ustring &r1, Glib::ustring &r2, Glib::ustring &r3, Glib::ustring &r4); - void setRangeDefaultMilestones(double m1, double m2, double m3); - void getRangeDefaultMilestones(double &m1, double &m2, double &m3); - - // set the reset curve for a given curve type. This is optional; all curve type have a default reset curve - void setResetCurve(DiagonalCurveType cType, const std::vector &resetCurve); -}; - - -/* - ********************** Flat Curve Editor ********************** - */ - - -class FlatCurveEditor : public CurveEditor { - - friend class FlatCurveEditorSubGroup; - - protected: - // reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value - std::vector controlPointsCurveEd; - std::vector controlPointsResetCurve; - bool periodic; - double identityValue; - - public: - FlatCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup, bool isPeriodic = true); - virtual void setIdentityValue (const double iValue=0.5) { identityValue = iValue; } - virtual double getIdentityValue () { return identityValue; }; - std::vector getCurve (); - - // set the reset curve for a given curve type. This is optional; all curve type have a default reset curve - void setResetCurve(FlatCurveType cType, const std::vector &resetCurve); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _CURVEEDITOR_ +#define _CURVEEDITOR_ + +#include "popuptogglebutton.h" +#include "../rtengine/LUT.h" +#include "coloredbar.h" +#include "edit.h" +#include "mydiagonalcurve.h" +#include "myflatcurve.h" + +class CurveEditorGroup; +class CurveEditorSubGroup; + + +/* + *********************** Curve Editor *********************** + */ + + +/* + * This class is an interface between RT and the curve editor group ; it handles the methods + * related to a specific curve. It is created by CurveEditorGroup::addCurve + */ +class CurveEditor : public EditSubscriber { + + friend class CurveEditorGroup; + friend class CurveEditorSubGroup; + friend class DiagonalCurveEditorSubGroup; + friend class FlatCurveEditorSubGroup; + friend class DiagonalCurveEditor; + friend class FlatCurveEditor; + + protected: + + /* + * The curve editor contains only one widget (the curve type button) to receive the signals + * but it's co-handled by the CurveEditorGroup too + */ + + PopUpToggleButton* curveType; + LUTu histogram; // histogram values + bool bgHistValid; + + bool remoteDrag; + + int selected; + + CurveEditorGroup* group; + CurveEditorSubGroup* subGroup; + Gtk::Widget* relatedWidget; + + std::vector tempCurve; + sigc::connection typeconn; + + ColorProvider* bottomBarCP; + ColorProvider* leftBarCP; + ColorProvider* curveCP; + int bottomBarCId; + int leftBarCId; + int curveCId; + std::vector bottomBarBgGradient; + std::vector leftBarBgGradient; + + sigc::signal sig_curvegraph_enter; + sigc::signal sig_curvegraph_leave; + sigc::signal sig_curvepoint_click; + sigc::signal sig_curvepoint_release; + + public: + + CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup); + virtual ~CurveEditor (); + void typeSelectionChanged (int n); + void curveTypeToggled(); + bool isUnChanged (); + void setUnChanged (bool uc); + void updateBackgroundHistogram (LUTu & hist); + + void setLeftBarColorProvider(ColorProvider* cp, int callerId); + void setBottomBarColorProvider(ColorProvider* cp, int callerId); + void setCurveColorProvider(ColorProvider* cp, int callerId); + void setBottomBarBgGradient (const std::vector &milestones); + void setLeftBarBgGradient (const std::vector &milestones); + ColorProvider* getLeftBarColorProvider(); + ColorProvider* getBottomBarColorProvider(); + ColorProvider* getCurveColorProvider(); + int getLeftBarCallerId(); + int getBottomBarCallerId(); + int getCurveCallerId(); + std::vector getBottomBarBgGradient () const; + std::vector getLeftBarBgGradient () const; + + void refresh (); // refresh the display of the CurveEditor (e.g. when a ColoredBar has been changed from the outside) + bool openIfNonlinear(); // Open up the curve if it has modifications and it's not already opened + + void setCurve (const std::vector& p); + virtual void setIdentityValue (const double iValue=0.5) {}; + virtual double getIdentityValue () { return 0.5; }; + virtual std::vector getCurve () = 0; + bool reset(); + void setTooltip(Glib::ustring ttip); + + sigc::signal signal_curvegraph_enter(); + sigc::signal signal_curvegraph_leave(); + sigc::signal signal_curvepoint_click(); + sigc::signal signal_curvepoint_release(); + + void switchOffEditMode (); + bool mouseOver(int modifierKey); + bool button1Pressed(int modifierKey); + bool button1Released(); + bool drag(int modifierKey); + CursorShape getCursor(int objectID); + + +}; + + +/* + ******************** Diagonal Curve Editor ******************** + */ + + +class DiagonalCurveEditor : public CurveEditor { + + friend class DiagonalCurveEditorSubGroup; + + protected: + // reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value + std::vector customCurveEd; + std::vector customResetCurve; + std::vector paramCurveEd; + std::vector paramResetCurve; + std::vector NURBSCurveEd; + std::vector NURBSResetCurve; + Glib::ustring rangeLabels[4]; + double rangeMilestones[3]; + + public: + DiagonalCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup); + std::vector getCurve (); + void setRangeLabels(Glib::ustring r1, Glib::ustring r2, Glib::ustring r3, Glib::ustring r4); + void getRangeLabels(Glib::ustring &r1, Glib::ustring &r2, Glib::ustring &r3, Glib::ustring &r4); + void setRangeDefaultMilestones(double m1, double m2, double m3); + void getRangeDefaultMilestones(double &m1, double &m2, double &m3); + + // set the reset curve for a given curve type. This is optional; all curve type have a default reset curve + void setResetCurve(DiagonalCurveType cType, const std::vector &resetCurve); +}; + + +/* + ********************** Flat Curve Editor ********************** + */ + + +class FlatCurveEditor : public CurveEditor { + + friend class FlatCurveEditorSubGroup; + + protected: + // reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value + std::vector controlPointsCurveEd; + std::vector controlPointsResetCurve; + bool periodic; + double identityValue; + + public: + FlatCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup, bool isPeriodic = true); + virtual void setIdentityValue (const double iValue=0.5) { identityValue = iValue; } + virtual double getIdentityValue () { return identityValue; }; + std::vector getCurve (); + + // set the reset curve for a given curve type. This is optional; all curve type have a default reset curve + void setResetCurve(FlatCurveType cType, const std::vector &resetCurve); +}; + +#endif diff --git a/rtgui/curveeditorgroup.h b/rtgui/curveeditorgroup.h index 8367d3b32..052633f84 100644 --- a/rtgui/curveeditorgroup.h +++ b/rtgui/curveeditorgroup.h @@ -1,156 +1,156 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _CURVEEDITORGROUP_ -#define _CURVEEDITORGROUP_ - -#include -#include -#include -#include "guiutils.h" -#include "mycurve.h" -#include "myflatcurve.h" -#include "mydiagonalcurve.h" -#include "shcselector.h" -#include "adjuster.h" - -class CurveEditor; -class DiagonalCurveEditorSubGroup; -class FlatCurveEditorSubGroup; - -/* - * This class handle the curve widgets, shared between any number curve - * - to add a curve to the list, use the 'addCurve' method - * - to start a new line of curve button, use the 'newLine' method - * - if you add more than one curve, you must add a "CurveEditor* ce" parameter to your listener - */ -class CurveEditorGroup : public Gtk::VBox, public CurveListener { - - friend class CurveEditor; - friend class CurveEditorSubGroup; - friend class DiagonalCurveEditorSubGroup; - friend class FlatCurveEditorSubGroup; - -private: - Glib::ustring& curveDir; - -protected: - Gtk::Label* curveGroupLabel; - Gtk::Button* curve_reset; - std::vector curveEditors; - CurveEditor* displayedCurve; - FlatCurveEditorSubGroup* flatSubGroup; - DiagonalCurveEditorSubGroup* diagonalSubGroup; - - CurveListener* cl; - - unsigned int numberOfPackedCurve; - -public: - /** - * @param curveDir The folder used by load and save dialogs for the curve. - * This variable will be updated with actions in the - * dialogs. - */ - - CurveEditorGroup(Glib::ustring& curveDir, Glib::ustring groupLabel = ""); - ~CurveEditorGroup(); - void newLine(); - void curveListComplete(); - void setBatchMode (bool batchMode); - void setCurveExternal (CurveEditor* ce, const std::vector& c); - void setCurveListener (CurveListener* l) { cl = l; } - void setTooltip (Glib::ustring ttip); - CurveEditor* getDisplayedCurve () { return displayedCurve; } - //void on_realize (); - CurveEditor* addCurve(CurveType cType, Glib::ustring curveLabel, Gtk::Widget *relatedWidget=NULL, bool periodic=true); - -protected: - //void curveTypeToggled (); - void curveTypeToggled (CurveEditor* ce); - //void typeSelectionChanged (int n); - void typeSelectionChanged (CurveEditor* ce, int n); - void hideCurrentCurve (); - void updateGUI (CurveEditor* ce); - void curveResetPressed (); - void curveChanged (); - float blendPipetteValues(CurveEditor* ce, float chan1, float chan2, float chan3); - void setUnChanged (bool uc, CurveEditor* ce); -}; - -class CoordinateProvider; - -class CurveEditorSubGroup { - - friend class CurveEditorGroup; - -private: - Glib::ustring& curveDir; - Glib::ustring lastFilename; - -protected: - int valLinear; - int valUnchanged; - CurveEditorGroup *parent; - int curveBBoxPos; // 0=above, 1=right, 2=below, 3=left - - ColoredBar* leftBar; - ColoredBar* bottomBar; - - -public: - virtual ~CurveEditorSubGroup(); - int getValUnchanged() { return valUnchanged; } - int getValLinear() { return valLinear; } - void updateEditButton(CurveEditor* curve, Gtk::ToggleButton *button, sigc::connection &connection); - virtual void updateBackgroundHistogram (CurveEditor* ce) {} - virtual void switchGUI() = 0; - virtual void refresh(CurveEditor *curveToRefresh) = 0; - virtual void editModeSwitchedOff() = 0; - - virtual void showCoordinateAdjuster(CoordinateProvider *provider) = 0; - virtual void stopNumericalAdjustment() = 0; - - virtual void pipetteMouseOver(EditDataProvider *provider, int modifierKey) =0; - virtual void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) =0; - virtual void pipetteButton1Released(EditDataProvider *provider) =0; - virtual void pipetteDrag(EditDataProvider *provider, int modifierKey) =0; - - virtual bool curveReset (CurveEditor *ce) = 0; // Reset a curve editor, return TRUE if successful (curve changed) - -protected: - - /** - * @param curveDir The folder used by load and save dialogs for the curve. - * This variable will be updated with actions in the - * dialogs. - */ - CurveEditorSubGroup(Glib::ustring& curveDir); - - Glib::ustring outputFile (); - Glib::ustring inputFile (); - - virtual void storeCurveValues (CurveEditor* ce, const std::vector& p) = 0; - virtual void storeDisplayedCurve () = 0; - virtual void restoreDisplayedHistogram() {}; - virtual void removeEditor () = 0; - virtual const std::vector getCurveFromGUI (int type) = 0; - -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _CURVEEDITORGROUP_ +#define _CURVEEDITORGROUP_ + +#include +#include +#include +#include "guiutils.h" +#include "mycurve.h" +#include "myflatcurve.h" +#include "mydiagonalcurve.h" +#include "shcselector.h" +#include "adjuster.h" + +class CurveEditor; +class DiagonalCurveEditorSubGroup; +class FlatCurveEditorSubGroup; + +/* + * This class handle the curve widgets, shared between any number curve + * - to add a curve to the list, use the 'addCurve' method + * - to start a new line of curve button, use the 'newLine' method + * - if you add more than one curve, you must add a "CurveEditor* ce" parameter to your listener + */ +class CurveEditorGroup : public Gtk::VBox, public CurveListener { + + friend class CurveEditor; + friend class CurveEditorSubGroup; + friend class DiagonalCurveEditorSubGroup; + friend class FlatCurveEditorSubGroup; + +private: + Glib::ustring& curveDir; + +protected: + Gtk::Label* curveGroupLabel; + Gtk::Button* curve_reset; + std::vector curveEditors; + CurveEditor* displayedCurve; + FlatCurveEditorSubGroup* flatSubGroup; + DiagonalCurveEditorSubGroup* diagonalSubGroup; + + CurveListener* cl; + + unsigned int numberOfPackedCurve; + +public: + /** + * @param curveDir The folder used by load and save dialogs for the curve. + * This variable will be updated with actions in the + * dialogs. + */ + + CurveEditorGroup(Glib::ustring& curveDir, Glib::ustring groupLabel = ""); + ~CurveEditorGroup(); + void newLine(); + void curveListComplete(); + void setBatchMode (bool batchMode); + void setCurveExternal (CurveEditor* ce, const std::vector& c); + void setCurveListener (CurveListener* l) { cl = l; } + void setTooltip (Glib::ustring ttip); + CurveEditor* getDisplayedCurve () { return displayedCurve; } + //void on_realize (); + CurveEditor* addCurve(CurveType cType, Glib::ustring curveLabel, Gtk::Widget *relatedWidget=NULL, bool periodic=true); + +protected: + //void curveTypeToggled (); + void curveTypeToggled (CurveEditor* ce); + //void typeSelectionChanged (int n); + void typeSelectionChanged (CurveEditor* ce, int n); + void hideCurrentCurve (); + void updateGUI (CurveEditor* ce); + void curveResetPressed (); + void curveChanged (); + float blendPipetteValues(CurveEditor* ce, float chan1, float chan2, float chan3); + void setUnChanged (bool uc, CurveEditor* ce); +}; + +class CoordinateProvider; + +class CurveEditorSubGroup { + + friend class CurveEditorGroup; + +private: + Glib::ustring& curveDir; + Glib::ustring lastFilename; + +protected: + int valLinear; + int valUnchanged; + CurveEditorGroup *parent; + int curveBBoxPos; // 0=above, 1=right, 2=below, 3=left + + ColoredBar* leftBar; + ColoredBar* bottomBar; + + +public: + virtual ~CurveEditorSubGroup(); + int getValUnchanged() { return valUnchanged; } + int getValLinear() { return valLinear; } + void updateEditButton(CurveEditor* curve, Gtk::ToggleButton *button, sigc::connection &connection); + virtual void updateBackgroundHistogram (CurveEditor* ce) {} + virtual void switchGUI() = 0; + virtual void refresh(CurveEditor *curveToRefresh) = 0; + virtual void editModeSwitchedOff() = 0; + + virtual void showCoordinateAdjuster(CoordinateProvider *provider) = 0; + virtual void stopNumericalAdjustment() = 0; + + virtual void pipetteMouseOver(EditDataProvider *provider, int modifierKey) =0; + virtual void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) =0; + virtual void pipetteButton1Released(EditDataProvider *provider) =0; + virtual void pipetteDrag(EditDataProvider *provider, int modifierKey) =0; + + virtual bool curveReset (CurveEditor *ce) = 0; // Reset a curve editor, return TRUE if successful (curve changed) + +protected: + + /** + * @param curveDir The folder used by load and save dialogs for the curve. + * This variable will be updated with actions in the + * dialogs. + */ + CurveEditorSubGroup(Glib::ustring& curveDir); + + Glib::ustring outputFile (); + Glib::ustring inputFile (); + + virtual void storeCurveValues (CurveEditor* ce, const std::vector& p) = 0; + virtual void storeDisplayedCurve () = 0; + virtual void restoreDisplayedHistogram() {}; + virtual void removeEditor () = 0; + virtual const std::vector getCurveFromGUI (int type) = 0; + +}; + +#endif diff --git a/rtgui/darkframe.cc b/rtgui/darkframe.cc index fb8f9787e..baf0e8f89 100644 --- a/rtgui/darkframe.cc +++ b/rtgui/darkframe.cc @@ -1,212 +1,212 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "darkframe.h" -#include "options.h" -#include "guiutils.h" -#include "../rtengine/safegtk.h" -#include -#include "rtimage.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -DarkFrame::DarkFrame () : FoldableToolPanel(this, "darkframe", M("TP_DARKFRAME_LABEL")) -{ - hbdf = Gtk::manage(new Gtk::HBox()); - hbdf->set_spacing(4); - darkFrameFile = Gtk::manage(new MyFileChooserButton(M("TP_DARKFRAME_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); - darkFrameFilePersister.reset(new FileChooserLastFolderPersister(darkFrameFile, options.lastDarkframeDir)); - dfLabel = Gtk::manage(new Gtk::Label(M("GENERAL_FILE"))); - btnReset = Gtk::manage(new Gtk::Button()); - btnReset->set_image (*Gtk::manage(new RTImage ("gtk-cancel.png"))); - hbdf->pack_start(*dfLabel, Gtk::PACK_SHRINK, 0); - hbdf->pack_start(*darkFrameFile); - hbdf->pack_start(*btnReset, Gtk::PACK_SHRINK, 0); - dfAuto = Gtk::manage(new Gtk::CheckButton((M("TP_DARKFRAME_AUTOSELECT")))); - dfInfo = Gtk::manage(new Gtk::Label("")); - dfInfo->set_alignment(0,0); //left align - - pack_start( *hbdf, Gtk::PACK_SHRINK, 0); - pack_start( *dfAuto, Gtk::PACK_SHRINK, 0); - pack_start( *dfInfo, Gtk::PACK_SHRINK, 0); - - dfautoconn = dfAuto->signal_toggled().connect ( sigc::mem_fun(*this, &DarkFrame::dfAutoChanged), true); - dfFile = darkFrameFile->signal_file_set().connect ( sigc::mem_fun(*this, &DarkFrame::darkFrameChanged), true); - btnReset->signal_clicked().connect( sigc::mem_fun(*this, &DarkFrame::darkFrameReset), true ); - - // Set filename filters - b_filter_asCurrent = false; - Gtk::FileFilter *filter_any = Gtk::manage(new Gtk::FileFilter); - filter_any->add_pattern("*"); - filter_any->set_name(M("FILECHOOSER_FILTER_ANY")); - darkFrameFile->add_filter (*filter_any); - - // filters for all supported non-raw extensions - for (size_t i=0; iadd_pattern("*." + options.parseExtensions[i]); - filter_df->add_pattern("*." + options.parseExtensions[i].uppercase()); - filter_df->set_name(options.parseExtensions[i].uppercase()); - darkFrameFile->add_filter (*filter_df); - //printf("adding filter %s \n",options.parseExtensions[i].uppercase().c_str()); - } - } -} - -void DarkFrame::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - dfautoconn.block(true); - - dfAuto->set_active( pp->raw.df_autoselect ); - - if(pedited ){ - dfAuto->set_inconsistent(!pedited->raw.dfAuto ); - } - if (safe_file_test (pp->raw.dark_frame, Glib::FILE_TEST_EXISTS)) - darkFrameFile->set_filename (pp->raw.dark_frame); - else - darkFrameReset(); - hbdf->set_sensitive( !pp->raw.df_autoselect ); - - lastDFauto = pp->raw.df_autoselect; - - if( pp->raw.df_autoselect && dfp && !multiImage){ - // retrieve the auto-selected df filename - rtengine::RawImage *img = dfp->getDF(); - if( img ){ - dfInfo->set_text( Glib::ustring::compose("%1: %2ISO %3s", Glib::path_get_basename(img->get_filename()), img->get_ISOspeed(), img->get_shutter()) ); - }else{ - dfInfo->set_text(Glib::ustring(M("TP_PREPROCESS_NO_FOUND"))); - } - } - else dfInfo->set_text(""); - - dfChanged = false; - - dfautoconn.block(false); - enableListener (); - - // Add filter with the current file extension if the current file is raw - if (dfp && !batchMode){ - - if (b_filter_asCurrent){ - //First, remove last filter_asCurrent if it was set for a raw file - std::vector filters = darkFrameFile->list_filters(); - darkFrameFile->remove_filter(**(filters.end()-1)); - b_filter_asCurrent = false; - } - - Glib::ustring fname = Glib::path_get_basename(dfp->GetCurrentImageFilePath()); - Glib::ustring filetype; - - if (fname!=""){ - // get image filetype, set filter to the same as current image's filetype - std::string::size_type idx; - idx = fname.rfind('.'); - if(idx != std::string::npos){ - filetype = fname.substr(idx+1); - israw = filetype.uppercase()!="JPG" && filetype.uppercase()!="JPEG" && filetype.uppercase()!="PNG" && filetype.uppercase()!="TIF" && filetype.uppercase()!="TIFF"; - - //exclude non-raw - if (israw) - { - b_filter_asCurrent = true; - Gtk::FileFilter *filter_asCurrent = Gtk::manage(new Gtk::FileFilter); - filter_asCurrent->add_pattern("*." + filetype); - filter_asCurrent->set_name(M("FILECHOOSER_FILTER_SAME") + " (" + filetype + ")"); - darkFrameFile->add_filter (*filter_asCurrent); - darkFrameFile->set_filter (*filter_asCurrent); - } - } - } - } - -} - -void DarkFrame::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.dark_frame = darkFrameFile->get_filename(); - pp->raw.df_autoselect = dfAuto->get_active(); - - if (pedited) { - pedited->raw.darkFrame = dfChanged; - pedited->raw.dfAuto = !dfAuto->get_inconsistent(); - } - -} - -void DarkFrame::dfAutoChanged() -{ - if (batchMode) { - if (dfAuto->get_inconsistent()) { - dfAuto->set_inconsistent (false); - dfautoconn.block (true); - dfAuto->set_active (false); - dfautoconn.block (false); - } - else if (lastDFauto) - dfAuto->set_inconsistent (true); - - lastDFauto = dfAuto->get_active (); - } - - if(dfAuto->get_active() && dfp && !batchMode){ - // retrieve the auto-selected df filename - rtengine::RawImage *img = dfp->getDF(); - if( img ){ - dfInfo->set_text( Glib::ustring::compose("%1: %2ISO %3s", Glib::path_get_basename(img->get_filename()), img->get_ISOspeed(), img->get_shutter()) ); - }else{ - dfInfo->set_text(Glib::ustring(M("TP_PREPROCESS_NO_FOUND"))); - } - } - else{dfInfo->set_text("");} - - hbdf->set_sensitive( !dfAuto->get_active() ); - if (listener) - listener->panelChanged (EvPreProcessAutoDF, dfAuto->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); -} - -void DarkFrame::darkFrameChanged() -{ - dfChanged=true; - if (listener) - listener->panelChanged (EvPreProcessDFFile, Glib::path_get_basename(darkFrameFile->get_filename())); -} - -void DarkFrame::darkFrameReset() -{ - dfChanged=true; - -// caution: I had to make this hack, because set_current_folder() doesn't work correctly! -// Because szeva doesn't exist since he was committed to happy hunting ground in Issue 316 -// we can use him now for this hack - darkFrameFile->set_filename (options.lastDarkframeDir + "/szeva"); -// end of the hack - - if (!options.lastDarkframeDir.empty()) - darkFrameFile->set_current_folder(options.lastDarkframeDir); - - dfInfo->set_text(""); - if (listener) - listener->panelChanged (EvPreProcessDFFile, M("GENERAL_NONE")); - -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "darkframe.h" +#include "options.h" +#include "guiutils.h" +#include "../rtengine/safegtk.h" +#include +#include "rtimage.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +DarkFrame::DarkFrame () : FoldableToolPanel(this, "darkframe", M("TP_DARKFRAME_LABEL")) +{ + hbdf = Gtk::manage(new Gtk::HBox()); + hbdf->set_spacing(4); + darkFrameFile = Gtk::manage(new MyFileChooserButton(M("TP_DARKFRAME_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); + darkFrameFilePersister.reset(new FileChooserLastFolderPersister(darkFrameFile, options.lastDarkframeDir)); + dfLabel = Gtk::manage(new Gtk::Label(M("GENERAL_FILE"))); + btnReset = Gtk::manage(new Gtk::Button()); + btnReset->set_image (*Gtk::manage(new RTImage ("gtk-cancel.png"))); + hbdf->pack_start(*dfLabel, Gtk::PACK_SHRINK, 0); + hbdf->pack_start(*darkFrameFile); + hbdf->pack_start(*btnReset, Gtk::PACK_SHRINK, 0); + dfAuto = Gtk::manage(new Gtk::CheckButton((M("TP_DARKFRAME_AUTOSELECT")))); + dfInfo = Gtk::manage(new Gtk::Label("")); + dfInfo->set_alignment(0,0); //left align + + pack_start( *hbdf, Gtk::PACK_SHRINK, 0); + pack_start( *dfAuto, Gtk::PACK_SHRINK, 0); + pack_start( *dfInfo, Gtk::PACK_SHRINK, 0); + + dfautoconn = dfAuto->signal_toggled().connect ( sigc::mem_fun(*this, &DarkFrame::dfAutoChanged), true); + dfFile = darkFrameFile->signal_file_set().connect ( sigc::mem_fun(*this, &DarkFrame::darkFrameChanged), true); + btnReset->signal_clicked().connect( sigc::mem_fun(*this, &DarkFrame::darkFrameReset), true ); + + // Set filename filters + b_filter_asCurrent = false; + Gtk::FileFilter *filter_any = Gtk::manage(new Gtk::FileFilter); + filter_any->add_pattern("*"); + filter_any->set_name(M("FILECHOOSER_FILTER_ANY")); + darkFrameFile->add_filter (*filter_any); + + // filters for all supported non-raw extensions + for (size_t i=0; iadd_pattern("*." + options.parseExtensions[i]); + filter_df->add_pattern("*." + options.parseExtensions[i].uppercase()); + filter_df->set_name(options.parseExtensions[i].uppercase()); + darkFrameFile->add_filter (*filter_df); + //printf("adding filter %s \n",options.parseExtensions[i].uppercase().c_str()); + } + } +} + +void DarkFrame::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + dfautoconn.block(true); + + dfAuto->set_active( pp->raw.df_autoselect ); + + if(pedited ){ + dfAuto->set_inconsistent(!pedited->raw.dfAuto ); + } + if (safe_file_test (pp->raw.dark_frame, Glib::FILE_TEST_EXISTS)) + darkFrameFile->set_filename (pp->raw.dark_frame); + else + darkFrameReset(); + hbdf->set_sensitive( !pp->raw.df_autoselect ); + + lastDFauto = pp->raw.df_autoselect; + + if( pp->raw.df_autoselect && dfp && !multiImage){ + // retrieve the auto-selected df filename + rtengine::RawImage *img = dfp->getDF(); + if( img ){ + dfInfo->set_text( Glib::ustring::compose("%1: %2ISO %3s", Glib::path_get_basename(img->get_filename()), img->get_ISOspeed(), img->get_shutter()) ); + }else{ + dfInfo->set_text(Glib::ustring(M("TP_PREPROCESS_NO_FOUND"))); + } + } + else dfInfo->set_text(""); + + dfChanged = false; + + dfautoconn.block(false); + enableListener (); + + // Add filter with the current file extension if the current file is raw + if (dfp && !batchMode){ + + if (b_filter_asCurrent){ + //First, remove last filter_asCurrent if it was set for a raw file + std::vector filters = darkFrameFile->list_filters(); + darkFrameFile->remove_filter(**(filters.end()-1)); + b_filter_asCurrent = false; + } + + Glib::ustring fname = Glib::path_get_basename(dfp->GetCurrentImageFilePath()); + Glib::ustring filetype; + + if (fname!=""){ + // get image filetype, set filter to the same as current image's filetype + std::string::size_type idx; + idx = fname.rfind('.'); + if(idx != std::string::npos){ + filetype = fname.substr(idx+1); + israw = filetype.uppercase()!="JPG" && filetype.uppercase()!="JPEG" && filetype.uppercase()!="PNG" && filetype.uppercase()!="TIF" && filetype.uppercase()!="TIFF"; + + //exclude non-raw + if (israw) + { + b_filter_asCurrent = true; + Gtk::FileFilter *filter_asCurrent = Gtk::manage(new Gtk::FileFilter); + filter_asCurrent->add_pattern("*." + filetype); + filter_asCurrent->set_name(M("FILECHOOSER_FILTER_SAME") + " (" + filetype + ")"); + darkFrameFile->add_filter (*filter_asCurrent); + darkFrameFile->set_filter (*filter_asCurrent); + } + } + } + } + +} + +void DarkFrame::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.dark_frame = darkFrameFile->get_filename(); + pp->raw.df_autoselect = dfAuto->get_active(); + + if (pedited) { + pedited->raw.darkFrame = dfChanged; + pedited->raw.dfAuto = !dfAuto->get_inconsistent(); + } + +} + +void DarkFrame::dfAutoChanged() +{ + if (batchMode) { + if (dfAuto->get_inconsistent()) { + dfAuto->set_inconsistent (false); + dfautoconn.block (true); + dfAuto->set_active (false); + dfautoconn.block (false); + } + else if (lastDFauto) + dfAuto->set_inconsistent (true); + + lastDFauto = dfAuto->get_active (); + } + + if(dfAuto->get_active() && dfp && !batchMode){ + // retrieve the auto-selected df filename + rtengine::RawImage *img = dfp->getDF(); + if( img ){ + dfInfo->set_text( Glib::ustring::compose("%1: %2ISO %3s", Glib::path_get_basename(img->get_filename()), img->get_ISOspeed(), img->get_shutter()) ); + }else{ + dfInfo->set_text(Glib::ustring(M("TP_PREPROCESS_NO_FOUND"))); + } + } + else{dfInfo->set_text("");} + + hbdf->set_sensitive( !dfAuto->get_active() ); + if (listener) + listener->panelChanged (EvPreProcessAutoDF, dfAuto->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); +} + +void DarkFrame::darkFrameChanged() +{ + dfChanged=true; + if (listener) + listener->panelChanged (EvPreProcessDFFile, Glib::path_get_basename(darkFrameFile->get_filename())); +} + +void DarkFrame::darkFrameReset() +{ + dfChanged=true; + +// caution: I had to make this hack, because set_current_folder() doesn't work correctly! +// Because szeva doesn't exist since he was committed to happy hunting ground in Issue 316 +// we can use him now for this hack + darkFrameFile->set_filename (options.lastDarkframeDir + "/szeva"); +// end of the hack + + if (!options.lastDarkframeDir.empty()) + darkFrameFile->set_current_folder(options.lastDarkframeDir); + + dfInfo->set_text(""); + if (listener) + listener->panelChanged (EvPreProcessDFFile, M("GENERAL_NONE")); + +} diff --git a/rtgui/darkframe.h b/rtgui/darkframe.h index 92f475100..785db8dc5 100644 --- a/rtgui/darkframe.h +++ b/rtgui/darkframe.h @@ -1,66 +1,66 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _DARKFRAME_H_ -#define _DARKFRAME_H_ - -#include -#include -#include "toolpanel.h" -#include "../rtengine/rawimage.h" -#include "guiutils.h" - -class DFProvider { - public: - virtual rtengine::RawImage* getDF() = 0; - virtual Glib::ustring GetCurrentImageFilePath() = 0; - // add other info here -}; - -class DarkFrame : public ToolParamBlock, public FoldableToolPanel { - -protected: - - MyFileChooserButton *darkFrameFile; - std::auto_ptr darkFrameFilePersister; - Gtk::HBox *hbdf; - Gtk::Button *btnReset; - Gtk::Label *dfLabel; - Gtk::Label *dfInfo; - Gtk::CheckButton* dfAuto; - bool dfChanged; - bool lastDFauto; - DFProvider *dfp; - sigc::connection dfautoconn, dfFile; - bool b_filter_asCurrent; - bool israw; - -public: - - DarkFrame (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - - void darkFrameChanged (); - void darkFrameReset (); - void dfAutoChanged (); - void setDFProvider (DFProvider* p) { dfp = p; }; -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _DARKFRAME_H_ +#define _DARKFRAME_H_ + +#include +#include +#include "toolpanel.h" +#include "../rtengine/rawimage.h" +#include "guiutils.h" + +class DFProvider { + public: + virtual rtengine::RawImage* getDF() = 0; + virtual Glib::ustring GetCurrentImageFilePath() = 0; + // add other info here +}; + +class DarkFrame : public ToolParamBlock, public FoldableToolPanel { + +protected: + + MyFileChooserButton *darkFrameFile; + std::auto_ptr darkFrameFilePersister; + Gtk::HBox *hbdf; + Gtk::Button *btnReset; + Gtk::Label *dfLabel; + Gtk::Label *dfInfo; + Gtk::CheckButton* dfAuto; + bool dfChanged; + bool lastDFauto; + DFProvider *dfp; + sigc::connection dfautoconn, dfFile; + bool b_filter_asCurrent; + bool israw; + +public: + + DarkFrame (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + + void darkFrameChanged (); + void darkFrameReset (); + void dfAutoChanged (); + void setDFProvider (DFProvider* p) { dfp = p; }; +}; + +#endif diff --git a/rtgui/diagonalcurveeditorsubgroup.cc b/rtgui/diagonalcurveeditorsubgroup.cc index 2091e5a9d..adcb0e8db 100644 --- a/rtgui/diagonalcurveeditorsubgroup.cc +++ b/rtgui/diagonalcurveeditorsubgroup.cc @@ -1,1082 +1,1082 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include "clipboard.h" -#include -#include -#include -#include "guiutils.h" -#include "multilangmgr.h" -#include "mycurve.h" -#include "shcselector.h" -#include "adjuster.h" -#include "mycurve.h" -#include "mydiagonalcurve.h" -#include "curveeditor.h" -#include "diagonalcurveeditorsubgroup.h" - -DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt, Glib::ustring& curveDir) : CurveEditorSubGroup(curveDir) { - - editedAdjuster = NULL; - editedAdjusterValue = 0; - - curveBBoxPos = options.curvebboxpos; - - valLinear = (int)DCT_Linear; - valUnchanged = (int)DCT_Unchanged; - parent = prt; - - activeParamControl = -1; - - // custom curve - customCurveBox = new Gtk::VBox (); - customCurveBox->set_spacing(4); - Gtk::HBox* customCurveAndButtons = Gtk::manage (new Gtk::HBox ()); - customCurveAndButtons->set_spacing(4); - customCurve = Gtk::manage (new MyDiagonalCurve ()); - customCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); - customCurve->setType (DCT_Spline); - - Gtk::Box* custombbox; // curvebboxpos 0=above, 1=right, 2=below, 3=left - if (options.curvebboxpos==1 || options.curvebboxpos==3) { - custombbox = Gtk::manage (new Gtk::VBox ()); - } else { - custombbox = Gtk::manage (new Gtk::HBox ()); - } - custombbox->set_spacing(4); - - pasteCustom = Gtk::manage (new Gtk::Button ()); - pasteCustom->add (*Gtk::manage (new RTImage ("edit-paste.png"))); - copyCustom = Gtk::manage (new Gtk::Button ()); - copyCustom->add (*Gtk::manage (new RTImage ("edit-copy.png"))); - saveCustom = Gtk::manage (new Gtk::Button ()); - saveCustom->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); - loadCustom = Gtk::manage (new Gtk::Button ()); - loadCustom->add (*Gtk::manage (new RTImage ("gtk-open.png"))); - editPointCustom = Gtk::manage (new Gtk::ToggleButton ()); - editPointCustom->add (*Gtk::manage (new RTImage ("gtk-edit.png"))); - editPointCustom->set_tooltip_text(M("CURVEEDITOR_EDITPOINT_HINT")); - editCustom = Gtk::manage (new Gtk::ToggleButton()); - editCustom->add (*Gtk::manage (new RTImage ("editmodehand.png"))); - editCustom->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); - editCustom->hide(); - - custombbox->pack_end (*pasteCustom, Gtk::PACK_SHRINK, 0); - custombbox->pack_end (*copyCustom, Gtk::PACK_SHRINK, 0); - custombbox->pack_end (*saveCustom, Gtk::PACK_SHRINK, 0); - custombbox->pack_end (*loadCustom, Gtk::PACK_SHRINK, 0); - custombbox->pack_start(*editPointCustom, Gtk::PACK_SHRINK, 0); - custombbox->pack_start(*editCustom, Gtk::PACK_SHRINK, 0); - - customCurveAndButtons->pack_start (*customCurve, Gtk::PACK_EXPAND_WIDGET, 0); - customCurveAndButtons->pack_start (*custombbox, Gtk::PACK_SHRINK, 0); - customCurveBox->pack_start (*customCurveAndButtons, Gtk::PACK_EXPAND_WIDGET); - if (options.curvebboxpos==0) { - removeIfThere (customCurveAndButtons, custombbox, false); - customCurveBox->pack_start (*custombbox); - customCurveBox->reorder_child(*custombbox, 0); - } else if (options.curvebboxpos==2) { - removeIfThere (customCurveAndButtons, custombbox, false); - customCurveBox->pack_start (*custombbox); - } else if (options.curvebboxpos==3) { - customCurveAndButtons->reorder_child(*custombbox, 0); - } - - customCoordAdjuster = Gtk::manage (new CoordinateAdjuster(customCurve, this)); - customCurveBox->pack_start(*customCoordAdjuster, Gtk::PACK_SHRINK, 0); - if (options.curvebboxpos == 2) - customCurveBox->reorder_child(*customCoordAdjuster, 2); - customCoordAdjuster->show_all(); - - customCurveBox->show_all (); - customCoordAdjuster->hide(); - - saveCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); - loadCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); - copyCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); - pasteCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); - editPointCustomConn = editPointCustom->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editPointToggled), editPointCustom) ); - editCustomConn = editCustom->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editToggled), editCustom) ); - - saveCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); - loadCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); - copyCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); - pasteCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); - // Custom curve end - - - // NURBS curve - NURBSCurveBox = new Gtk::VBox (); - NURBSCurveBox->set_spacing(4); - Gtk::HBox* NURBSCurveAndButtons = Gtk::manage (new Gtk::HBox ()); - NURBSCurveAndButtons->set_spacing(4); - NURBSCurve = Gtk::manage (new MyDiagonalCurve ()); - NURBSCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); - NURBSCurve->setType (DCT_NURBS); - - Gtk::Box* NURBSbbox; - if (options.curvebboxpos==1 || options.curvebboxpos==3) { - NURBSbbox = Gtk::manage (new Gtk::VBox ()); - } else { - NURBSbbox = Gtk::manage (new Gtk::HBox ()); - } - NURBSbbox->set_spacing(4); - - pasteNURBS = Gtk::manage (new Gtk::Button ()); - pasteNURBS->add (*Gtk::manage (new RTImage ("edit-paste.png"))); - copyNURBS = Gtk::manage (new Gtk::Button ()); - copyNURBS->add (*Gtk::manage (new RTImage ("edit-copy.png"))); - saveNURBS = Gtk::manage (new Gtk::Button ()); - saveNURBS->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); - loadNURBS = Gtk::manage (new Gtk::Button ()); - loadNURBS->add (*Gtk::manage (new RTImage ("gtk-open.png"))); - editPointNURBS = Gtk::manage (new Gtk::ToggleButton ()); - editPointNURBS->add (*Gtk::manage (new RTImage ("gtk-edit.png"))); - editPointNURBS->set_tooltip_text(M("CURVEEDITOR_EDITPOINT_HINT")); - editNURBS = Gtk::manage (new Gtk::ToggleButton()); - editNURBS->add (*Gtk::manage (new RTImage ("editmodehand.png"))); - editNURBS->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); - editNURBS->hide(); - NURBSbbox->pack_end (*pasteNURBS, Gtk::PACK_SHRINK, 0); - NURBSbbox->pack_end (*copyNURBS, Gtk::PACK_SHRINK, 0); - NURBSbbox->pack_end (*saveNURBS, Gtk::PACK_SHRINK, 0); - NURBSbbox->pack_end (*loadNURBS, Gtk::PACK_SHRINK, 0); - NURBSbbox->pack_start(*editPointNURBS, Gtk::PACK_SHRINK, 0); - NURBSbbox->pack_start(*editNURBS, Gtk::PACK_SHRINK, 0); - - NURBSCurveAndButtons->pack_start (*NURBSCurve, Gtk::PACK_EXPAND_WIDGET, 0); - NURBSCurveAndButtons->pack_start (*NURBSbbox, Gtk::PACK_SHRINK, 0); - NURBSCurveBox->pack_start (*NURBSCurveAndButtons, Gtk::PACK_EXPAND_WIDGET); - if (options.curvebboxpos==0) { - removeIfThere (NURBSCurveAndButtons, NURBSbbox, false); - NURBSCurveBox->pack_start (*NURBSbbox); - NURBSCurveBox->reorder_child(*NURBSbbox, 0); - } else if (options.curvebboxpos==2) { - removeIfThere (NURBSCurveAndButtons, NURBSbbox, false); - NURBSCurveBox->pack_start (*NURBSbbox); - } else if (options.curvebboxpos==3) { - NURBSCurveAndButtons->reorder_child(*NURBSbbox, 0); - } - - NURBSCoordAdjuster = Gtk::manage (new CoordinateAdjuster(NURBSCurve, this)); - NURBSCurveBox->pack_start(*NURBSCoordAdjuster, Gtk::PACK_SHRINK, 0); - if (options.curvebboxpos == 2) - NURBSCurveBox->reorder_child(*NURBSCoordAdjuster, 2); - NURBSCoordAdjuster->show_all(); - - NURBSCurveBox->show_all (); - NURBSCoordAdjuster->hide(); - - saveNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); - loadNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); - pasteNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); - copyNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); - editPointNURBSConn = editPointNURBS->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editPointToggled), editPointNURBS) ); - editNURBSConn = editNURBS->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editToggled), editNURBS) ); - - saveNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); - loadNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); - pasteNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); - copyNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); - // NURBS curve end - - - // parametric curve - paramCurveBox = new Gtk::VBox (); - paramCurveBox->set_spacing(4); - Gtk::HBox* paramCurveAndButtons = Gtk::manage (new Gtk::HBox ()); - paramCurveAndButtons->set_spacing(4); - Gtk::VBox* paramCurveAndShcVBox = Gtk::manage (new Gtk::VBox ()); - paramCurve = Gtk::manage (new MyDiagonalCurve ()); - paramCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); - paramCurve->setType (DCT_Parametric); - - Gtk::Box* parambbox; - if (options.curvebboxpos==1 || options.curvebboxpos==3) { - parambbox = Gtk::manage (new Gtk::VBox ()); - } else { - parambbox = Gtk::manage (new Gtk::HBox ()); - } - parambbox->set_spacing(4); - - shcSelector = Gtk::manage (new SHCSelector ()); - shcSelector->set_size_request (GRAPH_SIZE-100, 10); // width, height - //* shcSelector->set_size_request ((GRAPH_SIZE+2*RADIUS)-20, 20); - - pasteParam = Gtk::manage (new Gtk::Button ()); - pasteParam->add (*Gtk::manage (new RTImage ("edit-paste.png"))); - copyParam = Gtk::manage (new Gtk::Button ()); - copyParam->add (*Gtk::manage (new RTImage ("edit-copy.png"))); - saveParam = Gtk::manage (new Gtk::Button ()); - saveParam->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); - loadParam = Gtk::manage (new Gtk::Button ()); - loadParam->add (*Gtk::manage (new RTImage ("gtk-open.png"))); - editParam = Gtk::manage (new Gtk::ToggleButton()); - editParam->add (*Gtk::manage (new RTImage ("editmodehand.png"))); - editParam->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); - editParam->hide(); - parambbox->pack_end (*pasteParam, Gtk::PACK_SHRINK, 0); - parambbox->pack_end (*copyParam, Gtk::PACK_SHRINK, 0); - parambbox->pack_end (*saveParam, Gtk::PACK_SHRINK, 0); - parambbox->pack_end (*loadParam, Gtk::PACK_SHRINK, 0); - parambbox->pack_start(*editParam, Gtk::PACK_SHRINK, 0); - - saveParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); - loadParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); - pasteParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); - copyParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); - editParamConn = editParam->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editToggled), editParam) ); - - saveParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); - loadParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); - pasteParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); - copyParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); - - highlights = Gtk::manage (new Adjuster (M("CURVEEDITOR_HIGHLIGHTS"), -100, 100, 1, 0)); - lights = Gtk::manage (new Adjuster (M("CURVEEDITOR_LIGHTS"), -100, 100, 1, 0)); - darks = Gtk::manage (new Adjuster (M("CURVEEDITOR_DARKS"), -100, 100, 1, 0)); - shadows = Gtk::manage (new Adjuster (M("CURVEEDITOR_SHADOWS"), -100, 100, 1, 0)); - - Gtk::EventBox* evhighlights = Gtk::manage (new Gtk::EventBox ()); - Gtk::EventBox* evlights = Gtk::manage (new Gtk::EventBox ()); - Gtk::EventBox* evdarks = Gtk::manage (new Gtk::EventBox ()); - Gtk::EventBox* evshadows = Gtk::manage (new Gtk::EventBox ()); - - evhighlights->add (*highlights); - evlights->add (*lights); - evdarks->add (*darks); - evshadows->add (*shadows); - - // paramCurveSliderBox needed to set vspacing(4) between curve+shc and sliders without vspacing between each slider - Gtk::VBox* paramCurveSliderBox = Gtk::manage (new Gtk::VBox ()); - paramCurveSliderBox->set_spacing(4); - - paramCurveSliderBox->pack_start (*evhighlights); - paramCurveSliderBox->pack_start (*evlights); - paramCurveSliderBox->pack_start (*evdarks); - paramCurveSliderBox->pack_start (*evshadows); - - paramCurveBox->show_all (); - - paramCurveAndShcVBox->pack_start (*paramCurve, Gtk::PACK_EXPAND_WIDGET); - paramCurveAndShcVBox->pack_start (*shcSelector, Gtk::PACK_EXPAND_WIDGET); - paramCurveAndButtons->pack_start (*paramCurveAndShcVBox); - paramCurveAndButtons->pack_start (*parambbox, Gtk::PACK_SHRINK); - paramCurveBox->pack_start (*paramCurveAndButtons); - paramCurveBox->pack_start (*paramCurveSliderBox); - if (options.curvebboxpos==0) { - removeIfThere (paramCurveAndButtons, parambbox, false); - paramCurveBox->pack_start (*parambbox); - paramCurveBox->reorder_child(*parambbox, 0); - } else if (options.curvebboxpos==2) { - removeIfThere (paramCurveAndButtons, parambbox, false); - paramCurveBox->pack_start (*parambbox); - //paramCurveBox->reorder_child(*parambbox, 1); - } else if (options.curvebboxpos==3) { - paramCurveAndButtons->reorder_child(*parambbox, 0); - } - paramCurveBox->show_all (); - // parametric curve end - - - customCurveBox->reference (); - paramCurveBox->reference (); - - customCurve->setCurveListener (parent); // Send the message directly to the parent - NURBSCurve->setCurveListener (parent); - paramCurve->setCurveListener (parent); - shcSelector->setSHCListener (this); - - highlights->setAdjusterListener (this); - lights->setAdjusterListener (this); - darks->setAdjusterListener (this); - shadows->setAdjusterListener (this); - - evhighlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); - evlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); - evdarks->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); - evshadows->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); - evhighlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 4)); - evlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 5)); - evdarks->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 6)); - evshadows->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 7)); - evhighlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 4)); - evlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 5)); - evdarks->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 6)); - evshadows->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 7)); -} - -DiagonalCurveEditorSubGroup::~DiagonalCurveEditorSubGroup() { - delete customCurveBox; - delete paramCurveBox; - delete NURBSCurveBox; -} - -/* - * Add a new curve to the curves list - */ -DiagonalCurveEditor* DiagonalCurveEditorSubGroup::addCurve(Glib::ustring curveLabel) { - DiagonalCurveEditor* newCE = new DiagonalCurveEditor(curveLabel, parent, this); - - // Initialization of the new curve - storeCurveValues(newCE, getCurveFromGUI(DCT_Spline)); - storeCurveValues(newCE, getCurveFromGUI(DCT_Parametric)); - storeCurveValues(newCE, getCurveFromGUI(DCT_NURBS)); - return newCE; -} - -/* - * Switch off the edit button - */ -void DiagonalCurveEditorSubGroup::editModeSwitchedOff () { - // toggling off all edit buttons, even if only one is toggle on - bool prevState; - prevState = editCustomConn.block(true); - editCustom->set_active(false); - customCurve->pipetteMouseOver(NULL, NULL, 0); - customCurve->setDirty(true); - if (!prevState) editCustomConn.block(false); - prevState = editNURBSConn.block(true); - editNURBS->set_active(false); - NURBSCurve->pipetteMouseOver(NULL, NULL, 0); - NURBSCurve->setDirty(true); - if (!prevState) editNURBSConn.block(false); - prevState = editParamConn.block(true); - editParam->set_active(false); - paramCurve->pipetteMouseOver(NULL, NULL, 0); - paramCurve->setDirty(true); - if (!prevState) editParamConn.block(false); -} - -void DiagonalCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, int modifierKey) { - CurveEditor *curveEditor = static_cast(parent->displayedCurve); - switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) { - case (DCT_Spline): - customCurve->pipetteMouseOver(curveEditor, provider, modifierKey); - customCurve->setDirty(true); - break; - case (DCT_Parametric): - { - paramCurve->pipetteMouseOver(curveEditor, provider, modifierKey); - paramCurve->setDirty(true); - float pipetteVal = 0.f; - editedAdjuster = NULL; - int n = 0; - if (provider->pipetteVal[0] != -1.f) { - pipetteVal += provider->pipetteVal[0]; - ++n; - } - if (provider->pipetteVal[1] != -1.f) { - pipetteVal += provider->pipetteVal[1]; - ++n; - } - if (provider->pipetteVal[2] != -1.f) { - pipetteVal += provider->pipetteVal[2]; - ++n; - } - if (n>1) { - pipetteVal /= n; - } - else if (!n) - pipetteVal = -1.f; - - if (pipetteVal != -1.f) { - double pos[3]; - shcSelector->getPositions(pos[0], pos[1], pos[2]); - if (pipetteVal>=pos[2]) { - editedAdjuster = highlights; - paramCurve->setActiveParam(4); - } - else if(pipetteVal>=pos[1]) { - editedAdjuster = lights; - paramCurve->setActiveParam(5); - } - else if(pipetteVal>=pos[0]) { - editedAdjuster = darks; - paramCurve->setActiveParam(6); - } - else { - editedAdjuster = shadows; - paramCurve->setActiveParam(7); - } - } - else - paramCurve->setActiveParam(-1); - } - break; - case (DCT_NURBS): - NURBSCurve->pipetteMouseOver(curveEditor, provider, modifierKey); - NURBSCurve->setDirty(true); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } -} - -void DiagonalCurveEditorSubGroup::pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) { - CurveEditor *curveEditor = static_cast(parent->displayedCurve); - switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) { - case (DCT_Spline): - customCurve->pipetteButton1Pressed(provider, modifierKey); - break; - case (DCT_Parametric): - if (editedAdjuster) - editedAdjusterValue = editedAdjuster->getIntValue(); - break; - case (DCT_NURBS): - NURBSCurve->pipetteButton1Pressed(provider, modifierKey); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } -} - -void DiagonalCurveEditorSubGroup::pipetteButton1Released(EditDataProvider *provider) { - CurveEditor *curveEditor = static_cast(parent->displayedCurve); - switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) { - case (DCT_Spline): - customCurve->pipetteButton1Released(provider); - break; - case (DCT_Parametric): - editedAdjuster = NULL; - break; - case (DCT_NURBS): - NURBSCurve->pipetteButton1Released(provider); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } -} - -void DiagonalCurveEditorSubGroup::pipetteDrag(EditDataProvider *provider, int modifierKey) { - CurveEditor *curveEditor = static_cast(parent->displayedCurve); - switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) { - case (DCT_Spline): - customCurve->pipetteDrag(provider, modifierKey); - break; - case (DCT_Parametric): - if (editedAdjuster) { - int trimmedValue = editedAdjuster->trimValue(editedAdjusterValue-(provider->deltaScreen.y/2)); - if (trimmedValue != editedAdjuster->getIntValue()) { - editedAdjuster->setValue(trimmedValue); - adjusterChanged(editedAdjuster, trimmedValue); - } - } - break; - case (DCT_NURBS): - NURBSCurve->pipetteDrag(provider, modifierKey); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } -} - -void DiagonalCurveEditorSubGroup::showCoordinateAdjuster(CoordinateProvider *provider) { - if (provider == customCurve) { - if (!editPointCustom->get_active()) editPointCustom->set_active(true); - } - else if (provider == NURBSCurve) { - if (!editPointNURBS->get_active()) editPointNURBS->set_active(true); - } -} - -void DiagonalCurveEditorSubGroup::stopNumericalAdjustment() { - customCurve->stopNumericalAdjustment(); - NURBSCurve->stopNumericalAdjustment(); -} - -/* - * Force the resize of the curve editor, if the displayed one is the requested one - */ -void DiagonalCurveEditorSubGroup::refresh(CurveEditor *curveToRefresh) { - if (curveToRefresh != NULL && curveToRefresh == static_cast(parent->displayedCurve)) { - switch((DiagonalCurveType)(curveToRefresh->curveType->getSelected())) { - case (DCT_Spline): - customCurve->refresh(); - break; - case (DCT_Parametric): - paramCurve->refresh(); - shcSelector->refresh(); - break; - case (DCT_NURBS): - NURBSCurve->refresh(); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } - } -} - -/* - * Switch the editor widgets to the currently edited curve - */ -void DiagonalCurveEditorSubGroup::switchGUI() { - - removeEditor(); - - DiagonalCurveEditor* dCurve = static_cast(parent->displayedCurve); - - if (dCurve) { - - // Initializing GUI values + repacking the appropriated widget - //dCurve->typeconn.block(true); - - // first we update the colored bar - - ColorProvider *barColorProvider = dCurve->getLeftBarColorProvider(); - std::vector bgGradient = dCurve->getLeftBarBgGradient(); - if (barColorProvider == NULL && bgGradient.size() == 0) { - // dCurve has no left colored bar, so we delete the object - if (leftBar) { - delete leftBar; - leftBar = NULL; - } - } - else { - // dCurve ave a ColorProvider or a background gradient defined, so we create/update the object - if (!leftBar) { - leftBar = new ColoredBar(RTO_Bottom2Top); - } - if (barColorProvider) { - bgGradient.clear(); - leftBar->setColorProvider(barColorProvider, dCurve->getLeftBarCallerId()); - leftBar->setBgGradient (bgGradient); - } - else { - leftBar->setColorProvider(NULL, -1); - leftBar->setBgGradient (bgGradient); - } - } - - barColorProvider = dCurve->getBottomBarColorProvider(); - bgGradient = dCurve->getBottomBarBgGradient(); - if (barColorProvider == NULL && bgGradient.size() == 0) { - // dCurve has no bottom colored bar, so we delete the object - if (bottomBar) { - delete bottomBar; - bottomBar = NULL; - } - } - else { - // dCurve has a ColorProvider or a background gradient defined, so we create/update the object - if (!bottomBar) { - bottomBar = new ColoredBar(RTO_Left2Right); - } - if (barColorProvider) { - bgGradient.clear(); - bottomBar->setColorProvider(barColorProvider, dCurve->getBottomBarCallerId()); - bottomBar->setBgGradient (bgGradient); - } - else { - bottomBar->setColorProvider(NULL, -1); - bottomBar->setBgGradient (bgGradient); - } - } - - switch((DiagonalCurveType)(dCurve->curveType->getSelected())) { - case (DCT_Spline): - customCurve->setPoints (dCurve->customCurveEd); - customCurve->setColorProvider(dCurve->getCurveColorProvider(), dCurve->getCurveCallerId()); - customCurve->setColoredBar(leftBar, bottomBar); - customCurve->forceResize(); - updateEditButton(dCurve, editCustom, editCustomConn); - parent->pack_start (*customCurveBox); - customCurveBox->check_resize(); - break; - case (DCT_Parametric): - { - Glib::ustring label[4]; - dCurve->getRangeLabels(label[0], label[1], label[2], label[3]); - double mileStone[3]; - dCurve->getRangeDefaultMilestones(mileStone[0], mileStone[1], mileStone[2]); - paramCurve->setPoints (dCurve->paramCurveEd); - shcSelector->setDefaults(mileStone[0], mileStone[1], mileStone[2]); - shcSelector->setPositions ( - dCurve->paramCurveEd.at(1), - dCurve->paramCurveEd.at(2), - dCurve->paramCurveEd.at(3) - ); - - highlights->setValue (dCurve->paramCurveEd.at(4)); - highlights->setLabel(label[3]); - lights->setValue (dCurve->paramCurveEd.at(5)); - lights->setLabel(label[2]); - darks->setValue (dCurve->paramCurveEd.at(6)); - darks->setLabel(label[1]); - shadows->setValue (dCurve->paramCurveEd.at(7)); - shadows->setLabel(label[0]); - shcSelector->setColorProvider(barColorProvider, dCurve->getBottomBarCallerId()); - shcSelector->setBgGradient(bgGradient); - shcSelector->setMargins( (leftBar ? MyCurve::getBarWidth()+CBAR_MARGIN : RADIUS), RADIUS ); - paramCurve->setColoredBar(leftBar, NULL); - paramCurve->forceResize(); - updateEditButton(dCurve, editParam, editParamConn); - parent->pack_start (*paramCurveBox); - break; - } - case (DCT_NURBS): - NURBSCurve->setPoints (dCurve->NURBSCurveEd); - NURBSCurve->setColorProvider(dCurve->getCurveColorProvider(), dCurve->getCurveCallerId()); - NURBSCurve->setColoredBar(leftBar, bottomBar); - NURBSCurve->forceResize(); - updateEditButton(dCurve, editNURBS, editNURBSConn); - parent->pack_start (*NURBSCurveBox); - NURBSCurveBox->check_resize(); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } - - //dCurve->typeconn.block(false); - } -} - -void DiagonalCurveEditorSubGroup::savePressed () { - - Glib::ustring fname = outputFile(); - if (fname.size()) { - std::ofstream f (fname.c_str()); - std::vector p; - //std::vector p = customCurve->getPoints (); - - switch (parent->displayedCurve->selected) { - case DCT_Spline: // custom - p = customCurve->getPoints (); - break; - case DCT_NURBS: // NURBS - p = NURBSCurve->getPoints (); - break; - case DCT_Parametric: - p = paramCurve->getPoints (); - break; - default: - break; - } - - int ix = 0; - if (p[ix]==(double)(DCT_Linear)) - f << "Linear" << std::endl; - else if (p[ix]==(double)(DCT_Spline)) - f << "Spline" << std::endl; - else if (p[ix]==(double)(DCT_NURBS)) - f << "NURBS" << std::endl; - else if (p[ix]==(double)(DCT_Parametric)) - f << "Parametric" << std::endl; - if (p[ix]==(double)(DCT_Parametric)) { - ix++; - for (unsigned int i=0; i p; - std::string s; - f >> s; - if (s=="Linear") - p.push_back ((double)(DCT_Linear)); - else if (s=="Spline") - p.push_back ((double)(DCT_Spline)); - else if (s=="NURBS") - p.push_back ((double)(DCT_NURBS)); - else if (s=="Parametric") - p.push_back ((double)(DCT_Parametric)); - else return; - - double x; - while (f) { - f >> x; - if (f) - p.push_back (x); - } - if (p[0] == (double)(DCT_Spline)) { - customCurve->setPoints (p); - customCurve->queue_draw (); - customCurve->notifyListener (); - } - else if (p[0] == (double)(DCT_NURBS)) { - NURBSCurve->setPoints (p); - NURBSCurve->queue_draw (); - NURBSCurve->notifyListener (); - } - else if (p[0] == (double)(DCT_Parametric)) { - shcSelector->setPositions ( p[1], p[2], p[3] ); - highlights->setValue (p[4]); - lights->setValue (p[5]); - darks->setValue (p[6]); - shadows->setValue (p[7]); - paramCurve->setPoints (p); - paramCurve->queue_draw (); - paramCurve->notifyListener (); - } - } - } -} - -void DiagonalCurveEditorSubGroup::copyPressed () { -// For compatibility use enum DiagonalCurveType here - - std::vector curve; - - switch (parent->displayedCurve->selected) { - case DCT_Spline: // custom - curve = customCurve->getPoints (); - clipboard.setDiagonalCurveData (curve,DCT_Spline); - break; - case DCT_Parametric: // parametric - // ... do something, first add save/load functions - curve = paramCurve->getPoints (); - clipboard.setDiagonalCurveData (curve,DCT_Parametric); - break; - case DCT_NURBS: // NURBS - curve = NURBSCurve->getPoints (); - clipboard.setDiagonalCurveData (curve,DCT_NURBS); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } -} - -void DiagonalCurveEditorSubGroup::pastePressed () { -// For compatibility use enum DiagonalCurveType here - - std::vector curve; - DiagonalCurveType type; - - type = clipboard.hasDiagonalCurveData(); - - if (type == (DiagonalCurveType)parent->displayedCurve->selected) { - curve = clipboard.getDiagonalCurveData (); - switch (type) { - case DCT_Spline: // custom - customCurve->setPoints (curve); - customCurve->queue_draw (); - customCurve->notifyListener (); - break; - case DCT_Parametric: // parametric - // ... do something, first add save/load functions - shcSelector->setPositions ( - curve[1], - curve[2], - curve[3] ); - highlights->setValue (curve[4]); - lights->setValue (curve[5]); - darks->setValue (curve[6]); - shadows->setValue (curve[7]); - paramCurve->setPoints (curve); - paramCurve->queue_draw (); - paramCurve->notifyListener (); - break; - case DCT_NURBS: // NURBS - NURBSCurve->setPoints (curve); - NURBSCurve->queue_draw (); - NURBSCurve->notifyListener (); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } - } - return; -} - -void DiagonalCurveEditorSubGroup::editPointToggled(Gtk::ToggleButton *button) { - if (button->get_active()) { - customCoordAdjuster->show(); - NURBSCoordAdjuster->show(); - } - else { - if (customCoordAdjuster) { - customCurve->stopNumericalAdjustment(); - customCoordAdjuster->hide(); - NURBSCurve->stopNumericalAdjustment(); - NURBSCoordAdjuster->hide(); - } - } - if (button == editPointCustom) { - editPointNURBSConn.block(true); - editPointNURBS->set_active(!editPointNURBS->get_active()); - editPointNURBSConn.block(false); - } - else { - editPointCustomConn.block(true); - editPointCustom->set_active(!editPointCustom->get_active()); - editPointCustomConn.block(false); - } -} - -void DiagonalCurveEditorSubGroup::editToggled (Gtk::ToggleButton *button) { - DiagonalCurveEditor* dCurve = static_cast(parent->displayedCurve); - if (!dCurve) - // should never happen! - return; - - if (button->get_active()) { - dCurve->subscribe(); - if (button == editCustom) - customCurve->notifyListener (); - else if (button == editNURBS) - NURBSCurve->notifyListener (); - else if (button == editParam) - paramCurve->notifyListener (); - - /* - if (button != editCustom) { - editCustomConn.block(true); - editCustom->set_active(true); - editCustomConn.block(false); - } - else { - // will throw the event of curveChanged, which will now build the edit's buffer - customCurve->notifyListener (); - } - if (button != editNURBS) { - editNURBSConn.block(true); - editNURBS->set_active(true); - editNURBSConn.block(false); - } - else { - NURBSCurve->notifyListener (); - } - if (button != editParam) { - editParamConn.block(true); - editParam->set_active(true); - editParamConn.block(false); - } - else { - paramCurve->notifyListener (); - } - */ - } - else { - dCurve->unsubscribe(); - /* - if (button != editCustom ) { editCustomConn.block(true); editCustom->set_active(false); editCustomConn.block(false); } - if (button != editNURBS ) { editNURBSConn.block(true); editNURBS->set_active(false); editNURBSConn.block(false); } - if (button != editParam ) { editParamConn.block(true); editParam->set_active(false); editParamConn.block(false); } - */ - } -} - -/* - * Store the curves of the currently displayed type from the widgets to the CurveEditor object - */ -void DiagonalCurveEditorSubGroup::storeDisplayedCurve() { - if (parent->displayedCurve) { - switch (parent->displayedCurve->selected) { - case (DCT_Spline): - storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_Spline)); - break; - case (DCT_Parametric): - storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_Parametric)); - break; - case (DCT_NURBS): - storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_NURBS)); - break; - default: - break; - } - } -} - -/* - * Restore the histogram to all types from the CurveEditor object to the widgets - */ -void DiagonalCurveEditorSubGroup::restoreDisplayedHistogram() { - if (parent->displayedCurve /*&& initslope==1*/) { - paramCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); - customCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); - NURBSCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); - } - -} - -void DiagonalCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::vector& p) { - if (!p.empty()) { - DiagonalCurveType t = (DiagonalCurveType)p[0]; - - switch (t) { - case (DCT_Spline): - (static_cast(ce))->customCurveEd = p; - break; - case (DCT_Parametric): - (static_cast(ce))->paramCurveEd = p; - break; - case (DCT_NURBS): - (static_cast(ce))->NURBSCurveEd = p; - break; - default: - break; - } - } -} - -/* - * Called to update the parametric curve graph with new slider values - */ -const std::vector DiagonalCurveEditorSubGroup::getCurveFromGUI (int type) { - switch ((DiagonalCurveType)type) { - case (DCT_Parametric): { - std::vector lcurve (8); - lcurve[0] = (double)(DCT_Parametric); - shcSelector->getPositions (lcurve[1], lcurve[2], lcurve[3]); - lcurve[4] = highlights->getValue (); - lcurve[5] = lights->getValue (); - lcurve[6] = darks->getValue (); - lcurve[7] = shadows->getValue (); - return lcurve; - } - case (DCT_Spline): - return customCurve->getPoints (); - case (DCT_NURBS): - return NURBSCurve->getPoints (); - default: { - // linear and other solutions - std::vector lcurve (1); - lcurve[0] = (double)(DCT_Linear); - return lcurve; - } - } -} - -/* - * Unlink the tree editor widgets from their parent box to hide them - */ -void DiagonalCurveEditorSubGroup::removeEditor () { - removeIfThere (parent, customCurveBox, false); - removeIfThere (parent, paramCurveBox, false); - removeIfThere (parent, NURBSCurveBox, false); -} - -bool DiagonalCurveEditorSubGroup::curveReset(CurveEditor *ce) { - if (!ce) - return false; - - DiagonalCurveEditor *dce = static_cast(ce); - - switch (ce->selected) { - case (DCT_NURBS) : // = Control cage - NURBSCurve->reset (dce->NURBSResetCurve, dce->getIdentityValue()); - return true; - break; - case (DCT_Spline) : // = Custom - customCurve->reset (dce->customResetCurve, dce->getIdentityValue()); - return true; - break; - case (DCT_Parametric) : - { - DiagonalCurveEditor* dCurve = static_cast(parent->displayedCurve); - double mileStone[3]; - dCurve->getRangeDefaultMilestones(mileStone[0], mileStone[1], mileStone[2]); - - highlights->resetPressed(NULL); - lights->resetPressed(NULL); - darks->resetPressed(NULL); - shadows->resetPressed(NULL); - shcSelector->setDefaults(mileStone[0], mileStone[1], mileStone[2]); - shcSelector->reset(); - paramCurve->reset (dce->paramResetCurve, dce->getIdentityValue()); - return true; - break; - } - default: - return false; - break; - } - return true; -} - -/* - * Listener - */ -void DiagonalCurveEditorSubGroup::shcChanged () { - - paramCurve->setPoints (getCurveFromGUI(DCT_Parametric)); - storeDisplayedCurve(); - parent->curveChanged (); -} - -/* - * Listener - */ -void DiagonalCurveEditorSubGroup::adjusterChanged (Adjuster* a, double newval) { - - paramCurve->setPoints (getCurveFromGUI(DCT_Parametric)); - storeDisplayedCurve(); - parent->curveChanged (); -} - -/* - * Listener called when the mouse is over a parametric curve's slider - */ -bool DiagonalCurveEditorSubGroup::adjusterEntered (GdkEventCrossing* ev, int ac) { - - if (ev->detail != GDK_NOTIFY_INFERIOR) { - activeParamControl = ac; - paramCurve->setActiveParam (activeParamControl); - } - return true; -} - -/* - * Listener called when the mouse left the parametric curve's slider - */ -bool DiagonalCurveEditorSubGroup::adjusterLeft (GdkEventCrossing* ev, int ac) { - - if (ev->detail != GDK_NOTIFY_INFERIOR) { - activeParamControl = -1; - paramCurve->setActiveParam (activeParamControl); - } - return true; -} - -void DiagonalCurveEditorSubGroup::updateBackgroundHistogram (CurveEditor* ce) { - if (ce==parent->displayedCurve /*&& initslope==1*/) { - paramCurve->updateBackgroundHistogram (ce->histogram); - customCurve->updateBackgroundHistogram (ce->histogram); - NURBSCurve->updateBackgroundHistogram (ce->histogram); - } -} - -void DiagonalCurveEditorSubGroup::setSubGroupRangeLabels(Glib::ustring r1, Glib::ustring r2, Glib::ustring r3, Glib::ustring r4) { - shadows->setLabel(r1); - darks->setLabel(r2); - lights->setLabel(r3); - highlights->setLabel(r4); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "clipboard.h" +#include +#include +#include +#include "guiutils.h" +#include "multilangmgr.h" +#include "mycurve.h" +#include "shcselector.h" +#include "adjuster.h" +#include "mycurve.h" +#include "mydiagonalcurve.h" +#include "curveeditor.h" +#include "diagonalcurveeditorsubgroup.h" + +DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt, Glib::ustring& curveDir) : CurveEditorSubGroup(curveDir) { + + editedAdjuster = NULL; + editedAdjusterValue = 0; + + curveBBoxPos = options.curvebboxpos; + + valLinear = (int)DCT_Linear; + valUnchanged = (int)DCT_Unchanged; + parent = prt; + + activeParamControl = -1; + + // custom curve + customCurveBox = new Gtk::VBox (); + customCurveBox->set_spacing(4); + Gtk::HBox* customCurveAndButtons = Gtk::manage (new Gtk::HBox ()); + customCurveAndButtons->set_spacing(4); + customCurve = Gtk::manage (new MyDiagonalCurve ()); + customCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); + customCurve->setType (DCT_Spline); + + Gtk::Box* custombbox; // curvebboxpos 0=above, 1=right, 2=below, 3=left + if (options.curvebboxpos==1 || options.curvebboxpos==3) { + custombbox = Gtk::manage (new Gtk::VBox ()); + } else { + custombbox = Gtk::manage (new Gtk::HBox ()); + } + custombbox->set_spacing(4); + + pasteCustom = Gtk::manage (new Gtk::Button ()); + pasteCustom->add (*Gtk::manage (new RTImage ("edit-paste.png"))); + copyCustom = Gtk::manage (new Gtk::Button ()); + copyCustom->add (*Gtk::manage (new RTImage ("edit-copy.png"))); + saveCustom = Gtk::manage (new Gtk::Button ()); + saveCustom->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); + loadCustom = Gtk::manage (new Gtk::Button ()); + loadCustom->add (*Gtk::manage (new RTImage ("gtk-open.png"))); + editPointCustom = Gtk::manage (new Gtk::ToggleButton ()); + editPointCustom->add (*Gtk::manage (new RTImage ("gtk-edit.png"))); + editPointCustom->set_tooltip_text(M("CURVEEDITOR_EDITPOINT_HINT")); + editCustom = Gtk::manage (new Gtk::ToggleButton()); + editCustom->add (*Gtk::manage (new RTImage ("editmodehand.png"))); + editCustom->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); + editCustom->hide(); + + custombbox->pack_end (*pasteCustom, Gtk::PACK_SHRINK, 0); + custombbox->pack_end (*copyCustom, Gtk::PACK_SHRINK, 0); + custombbox->pack_end (*saveCustom, Gtk::PACK_SHRINK, 0); + custombbox->pack_end (*loadCustom, Gtk::PACK_SHRINK, 0); + custombbox->pack_start(*editPointCustom, Gtk::PACK_SHRINK, 0); + custombbox->pack_start(*editCustom, Gtk::PACK_SHRINK, 0); + + customCurveAndButtons->pack_start (*customCurve, Gtk::PACK_EXPAND_WIDGET, 0); + customCurveAndButtons->pack_start (*custombbox, Gtk::PACK_SHRINK, 0); + customCurveBox->pack_start (*customCurveAndButtons, Gtk::PACK_EXPAND_WIDGET); + if (options.curvebboxpos==0) { + removeIfThere (customCurveAndButtons, custombbox, false); + customCurveBox->pack_start (*custombbox); + customCurveBox->reorder_child(*custombbox, 0); + } else if (options.curvebboxpos==2) { + removeIfThere (customCurveAndButtons, custombbox, false); + customCurveBox->pack_start (*custombbox); + } else if (options.curvebboxpos==3) { + customCurveAndButtons->reorder_child(*custombbox, 0); + } + + customCoordAdjuster = Gtk::manage (new CoordinateAdjuster(customCurve, this)); + customCurveBox->pack_start(*customCoordAdjuster, Gtk::PACK_SHRINK, 0); + if (options.curvebboxpos == 2) + customCurveBox->reorder_child(*customCoordAdjuster, 2); + customCoordAdjuster->show_all(); + + customCurveBox->show_all (); + customCoordAdjuster->hide(); + + saveCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); + loadCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); + copyCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); + pasteCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); + editPointCustomConn = editPointCustom->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editPointToggled), editPointCustom) ); + editCustomConn = editCustom->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editToggled), editCustom) ); + + saveCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); + loadCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); + copyCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); + pasteCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); + // Custom curve end + + + // NURBS curve + NURBSCurveBox = new Gtk::VBox (); + NURBSCurveBox->set_spacing(4); + Gtk::HBox* NURBSCurveAndButtons = Gtk::manage (new Gtk::HBox ()); + NURBSCurveAndButtons->set_spacing(4); + NURBSCurve = Gtk::manage (new MyDiagonalCurve ()); + NURBSCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); + NURBSCurve->setType (DCT_NURBS); + + Gtk::Box* NURBSbbox; + if (options.curvebboxpos==1 || options.curvebboxpos==3) { + NURBSbbox = Gtk::manage (new Gtk::VBox ()); + } else { + NURBSbbox = Gtk::manage (new Gtk::HBox ()); + } + NURBSbbox->set_spacing(4); + + pasteNURBS = Gtk::manage (new Gtk::Button ()); + pasteNURBS->add (*Gtk::manage (new RTImage ("edit-paste.png"))); + copyNURBS = Gtk::manage (new Gtk::Button ()); + copyNURBS->add (*Gtk::manage (new RTImage ("edit-copy.png"))); + saveNURBS = Gtk::manage (new Gtk::Button ()); + saveNURBS->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); + loadNURBS = Gtk::manage (new Gtk::Button ()); + loadNURBS->add (*Gtk::manage (new RTImage ("gtk-open.png"))); + editPointNURBS = Gtk::manage (new Gtk::ToggleButton ()); + editPointNURBS->add (*Gtk::manage (new RTImage ("gtk-edit.png"))); + editPointNURBS->set_tooltip_text(M("CURVEEDITOR_EDITPOINT_HINT")); + editNURBS = Gtk::manage (new Gtk::ToggleButton()); + editNURBS->add (*Gtk::manage (new RTImage ("editmodehand.png"))); + editNURBS->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); + editNURBS->hide(); + NURBSbbox->pack_end (*pasteNURBS, Gtk::PACK_SHRINK, 0); + NURBSbbox->pack_end (*copyNURBS, Gtk::PACK_SHRINK, 0); + NURBSbbox->pack_end (*saveNURBS, Gtk::PACK_SHRINK, 0); + NURBSbbox->pack_end (*loadNURBS, Gtk::PACK_SHRINK, 0); + NURBSbbox->pack_start(*editPointNURBS, Gtk::PACK_SHRINK, 0); + NURBSbbox->pack_start(*editNURBS, Gtk::PACK_SHRINK, 0); + + NURBSCurveAndButtons->pack_start (*NURBSCurve, Gtk::PACK_EXPAND_WIDGET, 0); + NURBSCurveAndButtons->pack_start (*NURBSbbox, Gtk::PACK_SHRINK, 0); + NURBSCurveBox->pack_start (*NURBSCurveAndButtons, Gtk::PACK_EXPAND_WIDGET); + if (options.curvebboxpos==0) { + removeIfThere (NURBSCurveAndButtons, NURBSbbox, false); + NURBSCurveBox->pack_start (*NURBSbbox); + NURBSCurveBox->reorder_child(*NURBSbbox, 0); + } else if (options.curvebboxpos==2) { + removeIfThere (NURBSCurveAndButtons, NURBSbbox, false); + NURBSCurveBox->pack_start (*NURBSbbox); + } else if (options.curvebboxpos==3) { + NURBSCurveAndButtons->reorder_child(*NURBSbbox, 0); + } + + NURBSCoordAdjuster = Gtk::manage (new CoordinateAdjuster(NURBSCurve, this)); + NURBSCurveBox->pack_start(*NURBSCoordAdjuster, Gtk::PACK_SHRINK, 0); + if (options.curvebboxpos == 2) + NURBSCurveBox->reorder_child(*NURBSCoordAdjuster, 2); + NURBSCoordAdjuster->show_all(); + + NURBSCurveBox->show_all (); + NURBSCoordAdjuster->hide(); + + saveNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); + loadNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); + pasteNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); + copyNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); + editPointNURBSConn = editPointNURBS->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editPointToggled), editPointNURBS) ); + editNURBSConn = editNURBS->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editToggled), editNURBS) ); + + saveNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); + loadNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); + pasteNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); + copyNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); + // NURBS curve end + + + // parametric curve + paramCurveBox = new Gtk::VBox (); + paramCurveBox->set_spacing(4); + Gtk::HBox* paramCurveAndButtons = Gtk::manage (new Gtk::HBox ()); + paramCurveAndButtons->set_spacing(4); + Gtk::VBox* paramCurveAndShcVBox = Gtk::manage (new Gtk::VBox ()); + paramCurve = Gtk::manage (new MyDiagonalCurve ()); + paramCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS); + paramCurve->setType (DCT_Parametric); + + Gtk::Box* parambbox; + if (options.curvebboxpos==1 || options.curvebboxpos==3) { + parambbox = Gtk::manage (new Gtk::VBox ()); + } else { + parambbox = Gtk::manage (new Gtk::HBox ()); + } + parambbox->set_spacing(4); + + shcSelector = Gtk::manage (new SHCSelector ()); + shcSelector->set_size_request (GRAPH_SIZE-100, 10); // width, height + //* shcSelector->set_size_request ((GRAPH_SIZE+2*RADIUS)-20, 20); + + pasteParam = Gtk::manage (new Gtk::Button ()); + pasteParam->add (*Gtk::manage (new RTImage ("edit-paste.png"))); + copyParam = Gtk::manage (new Gtk::Button ()); + copyParam->add (*Gtk::manage (new RTImage ("edit-copy.png"))); + saveParam = Gtk::manage (new Gtk::Button ()); + saveParam->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); + loadParam = Gtk::manage (new Gtk::Button ()); + loadParam->add (*Gtk::manage (new RTImage ("gtk-open.png"))); + editParam = Gtk::manage (new Gtk::ToggleButton()); + editParam->add (*Gtk::manage (new RTImage ("editmodehand.png"))); + editParam->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); + editParam->hide(); + parambbox->pack_end (*pasteParam, Gtk::PACK_SHRINK, 0); + parambbox->pack_end (*copyParam, Gtk::PACK_SHRINK, 0); + parambbox->pack_end (*saveParam, Gtk::PACK_SHRINK, 0); + parambbox->pack_end (*loadParam, Gtk::PACK_SHRINK, 0); + parambbox->pack_start(*editParam, Gtk::PACK_SHRINK, 0); + + saveParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) ); + loadParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) ); + pasteParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::pastePressed) ); + copyParam->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::copyPressed) ); + editParamConn = editParam->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::editToggled), editParam) ); + + saveParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); + loadParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); + pasteParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); + copyParam->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); + + highlights = Gtk::manage (new Adjuster (M("CURVEEDITOR_HIGHLIGHTS"), -100, 100, 1, 0)); + lights = Gtk::manage (new Adjuster (M("CURVEEDITOR_LIGHTS"), -100, 100, 1, 0)); + darks = Gtk::manage (new Adjuster (M("CURVEEDITOR_DARKS"), -100, 100, 1, 0)); + shadows = Gtk::manage (new Adjuster (M("CURVEEDITOR_SHADOWS"), -100, 100, 1, 0)); + + Gtk::EventBox* evhighlights = Gtk::manage (new Gtk::EventBox ()); + Gtk::EventBox* evlights = Gtk::manage (new Gtk::EventBox ()); + Gtk::EventBox* evdarks = Gtk::manage (new Gtk::EventBox ()); + Gtk::EventBox* evshadows = Gtk::manage (new Gtk::EventBox ()); + + evhighlights->add (*highlights); + evlights->add (*lights); + evdarks->add (*darks); + evshadows->add (*shadows); + + // paramCurveSliderBox needed to set vspacing(4) between curve+shc and sliders without vspacing between each slider + Gtk::VBox* paramCurveSliderBox = Gtk::manage (new Gtk::VBox ()); + paramCurveSliderBox->set_spacing(4); + + paramCurveSliderBox->pack_start (*evhighlights); + paramCurveSliderBox->pack_start (*evlights); + paramCurveSliderBox->pack_start (*evdarks); + paramCurveSliderBox->pack_start (*evshadows); + + paramCurveBox->show_all (); + + paramCurveAndShcVBox->pack_start (*paramCurve, Gtk::PACK_EXPAND_WIDGET); + paramCurveAndShcVBox->pack_start (*shcSelector, Gtk::PACK_EXPAND_WIDGET); + paramCurveAndButtons->pack_start (*paramCurveAndShcVBox); + paramCurveAndButtons->pack_start (*parambbox, Gtk::PACK_SHRINK); + paramCurveBox->pack_start (*paramCurveAndButtons); + paramCurveBox->pack_start (*paramCurveSliderBox); + if (options.curvebboxpos==0) { + removeIfThere (paramCurveAndButtons, parambbox, false); + paramCurveBox->pack_start (*parambbox); + paramCurveBox->reorder_child(*parambbox, 0); + } else if (options.curvebboxpos==2) { + removeIfThere (paramCurveAndButtons, parambbox, false); + paramCurveBox->pack_start (*parambbox); + //paramCurveBox->reorder_child(*parambbox, 1); + } else if (options.curvebboxpos==3) { + paramCurveAndButtons->reorder_child(*parambbox, 0); + } + paramCurveBox->show_all (); + // parametric curve end + + + customCurveBox->reference (); + paramCurveBox->reference (); + + customCurve->setCurveListener (parent); // Send the message directly to the parent + NURBSCurve->setCurveListener (parent); + paramCurve->setCurveListener (parent); + shcSelector->setSHCListener (this); + + highlights->setAdjusterListener (this); + lights->setAdjusterListener (this); + darks->setAdjusterListener (this); + shadows->setAdjusterListener (this); + + evhighlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evdarks->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evshadows->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evhighlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 4)); + evlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 5)); + evdarks->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 6)); + evshadows->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 7)); + evhighlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 4)); + evlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 5)); + evdarks->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 6)); + evshadows->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 7)); +} + +DiagonalCurveEditorSubGroup::~DiagonalCurveEditorSubGroup() { + delete customCurveBox; + delete paramCurveBox; + delete NURBSCurveBox; +} + +/* + * Add a new curve to the curves list + */ +DiagonalCurveEditor* DiagonalCurveEditorSubGroup::addCurve(Glib::ustring curveLabel) { + DiagonalCurveEditor* newCE = new DiagonalCurveEditor(curveLabel, parent, this); + + // Initialization of the new curve + storeCurveValues(newCE, getCurveFromGUI(DCT_Spline)); + storeCurveValues(newCE, getCurveFromGUI(DCT_Parametric)); + storeCurveValues(newCE, getCurveFromGUI(DCT_NURBS)); + return newCE; +} + +/* + * Switch off the edit button + */ +void DiagonalCurveEditorSubGroup::editModeSwitchedOff () { + // toggling off all edit buttons, even if only one is toggle on + bool prevState; + prevState = editCustomConn.block(true); + editCustom->set_active(false); + customCurve->pipetteMouseOver(NULL, NULL, 0); + customCurve->setDirty(true); + if (!prevState) editCustomConn.block(false); + prevState = editNURBSConn.block(true); + editNURBS->set_active(false); + NURBSCurve->pipetteMouseOver(NULL, NULL, 0); + NURBSCurve->setDirty(true); + if (!prevState) editNURBSConn.block(false); + prevState = editParamConn.block(true); + editParam->set_active(false); + paramCurve->pipetteMouseOver(NULL, NULL, 0); + paramCurve->setDirty(true); + if (!prevState) editParamConn.block(false); +} + +void DiagonalCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, int modifierKey) { + CurveEditor *curveEditor = static_cast(parent->displayedCurve); + switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) { + case (DCT_Spline): + customCurve->pipetteMouseOver(curveEditor, provider, modifierKey); + customCurve->setDirty(true); + break; + case (DCT_Parametric): + { + paramCurve->pipetteMouseOver(curveEditor, provider, modifierKey); + paramCurve->setDirty(true); + float pipetteVal = 0.f; + editedAdjuster = NULL; + int n = 0; + if (provider->pipetteVal[0] != -1.f) { + pipetteVal += provider->pipetteVal[0]; + ++n; + } + if (provider->pipetteVal[1] != -1.f) { + pipetteVal += provider->pipetteVal[1]; + ++n; + } + if (provider->pipetteVal[2] != -1.f) { + pipetteVal += provider->pipetteVal[2]; + ++n; + } + if (n>1) { + pipetteVal /= n; + } + else if (!n) + pipetteVal = -1.f; + + if (pipetteVal != -1.f) { + double pos[3]; + shcSelector->getPositions(pos[0], pos[1], pos[2]); + if (pipetteVal>=pos[2]) { + editedAdjuster = highlights; + paramCurve->setActiveParam(4); + } + else if(pipetteVal>=pos[1]) { + editedAdjuster = lights; + paramCurve->setActiveParam(5); + } + else if(pipetteVal>=pos[0]) { + editedAdjuster = darks; + paramCurve->setActiveParam(6); + } + else { + editedAdjuster = shadows; + paramCurve->setActiveParam(7); + } + } + else + paramCurve->setActiveParam(-1); + } + break; + case (DCT_NURBS): + NURBSCurve->pipetteMouseOver(curveEditor, provider, modifierKey); + NURBSCurve->setDirty(true); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +void DiagonalCurveEditorSubGroup::pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) { + CurveEditor *curveEditor = static_cast(parent->displayedCurve); + switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) { + case (DCT_Spline): + customCurve->pipetteButton1Pressed(provider, modifierKey); + break; + case (DCT_Parametric): + if (editedAdjuster) + editedAdjusterValue = editedAdjuster->getIntValue(); + break; + case (DCT_NURBS): + NURBSCurve->pipetteButton1Pressed(provider, modifierKey); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +void DiagonalCurveEditorSubGroup::pipetteButton1Released(EditDataProvider *provider) { + CurveEditor *curveEditor = static_cast(parent->displayedCurve); + switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) { + case (DCT_Spline): + customCurve->pipetteButton1Released(provider); + break; + case (DCT_Parametric): + editedAdjuster = NULL; + break; + case (DCT_NURBS): + NURBSCurve->pipetteButton1Released(provider); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +void DiagonalCurveEditorSubGroup::pipetteDrag(EditDataProvider *provider, int modifierKey) { + CurveEditor *curveEditor = static_cast(parent->displayedCurve); + switch((DiagonalCurveType)(curveEditor->curveType->getSelected())) { + case (DCT_Spline): + customCurve->pipetteDrag(provider, modifierKey); + break; + case (DCT_Parametric): + if (editedAdjuster) { + int trimmedValue = editedAdjuster->trimValue(editedAdjusterValue-(provider->deltaScreen.y/2)); + if (trimmedValue != editedAdjuster->getIntValue()) { + editedAdjuster->setValue(trimmedValue); + adjusterChanged(editedAdjuster, trimmedValue); + } + } + break; + case (DCT_NURBS): + NURBSCurve->pipetteDrag(provider, modifierKey); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +void DiagonalCurveEditorSubGroup::showCoordinateAdjuster(CoordinateProvider *provider) { + if (provider == customCurve) { + if (!editPointCustom->get_active()) editPointCustom->set_active(true); + } + else if (provider == NURBSCurve) { + if (!editPointNURBS->get_active()) editPointNURBS->set_active(true); + } +} + +void DiagonalCurveEditorSubGroup::stopNumericalAdjustment() { + customCurve->stopNumericalAdjustment(); + NURBSCurve->stopNumericalAdjustment(); +} + +/* + * Force the resize of the curve editor, if the displayed one is the requested one + */ +void DiagonalCurveEditorSubGroup::refresh(CurveEditor *curveToRefresh) { + if (curveToRefresh != NULL && curveToRefresh == static_cast(parent->displayedCurve)) { + switch((DiagonalCurveType)(curveToRefresh->curveType->getSelected())) { + case (DCT_Spline): + customCurve->refresh(); + break; + case (DCT_Parametric): + paramCurve->refresh(); + shcSelector->refresh(); + break; + case (DCT_NURBS): + NURBSCurve->refresh(); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } + } +} + +/* + * Switch the editor widgets to the currently edited curve + */ +void DiagonalCurveEditorSubGroup::switchGUI() { + + removeEditor(); + + DiagonalCurveEditor* dCurve = static_cast(parent->displayedCurve); + + if (dCurve) { + + // Initializing GUI values + repacking the appropriated widget + //dCurve->typeconn.block(true); + + // first we update the colored bar + + ColorProvider *barColorProvider = dCurve->getLeftBarColorProvider(); + std::vector bgGradient = dCurve->getLeftBarBgGradient(); + if (barColorProvider == NULL && bgGradient.size() == 0) { + // dCurve has no left colored bar, so we delete the object + if (leftBar) { + delete leftBar; + leftBar = NULL; + } + } + else { + // dCurve ave a ColorProvider or a background gradient defined, so we create/update the object + if (!leftBar) { + leftBar = new ColoredBar(RTO_Bottom2Top); + } + if (barColorProvider) { + bgGradient.clear(); + leftBar->setColorProvider(barColorProvider, dCurve->getLeftBarCallerId()); + leftBar->setBgGradient (bgGradient); + } + else { + leftBar->setColorProvider(NULL, -1); + leftBar->setBgGradient (bgGradient); + } + } + + barColorProvider = dCurve->getBottomBarColorProvider(); + bgGradient = dCurve->getBottomBarBgGradient(); + if (barColorProvider == NULL && bgGradient.size() == 0) { + // dCurve has no bottom colored bar, so we delete the object + if (bottomBar) { + delete bottomBar; + bottomBar = NULL; + } + } + else { + // dCurve has a ColorProvider or a background gradient defined, so we create/update the object + if (!bottomBar) { + bottomBar = new ColoredBar(RTO_Left2Right); + } + if (barColorProvider) { + bgGradient.clear(); + bottomBar->setColorProvider(barColorProvider, dCurve->getBottomBarCallerId()); + bottomBar->setBgGradient (bgGradient); + } + else { + bottomBar->setColorProvider(NULL, -1); + bottomBar->setBgGradient (bgGradient); + } + } + + switch((DiagonalCurveType)(dCurve->curveType->getSelected())) { + case (DCT_Spline): + customCurve->setPoints (dCurve->customCurveEd); + customCurve->setColorProvider(dCurve->getCurveColorProvider(), dCurve->getCurveCallerId()); + customCurve->setColoredBar(leftBar, bottomBar); + customCurve->forceResize(); + updateEditButton(dCurve, editCustom, editCustomConn); + parent->pack_start (*customCurveBox); + customCurveBox->check_resize(); + break; + case (DCT_Parametric): + { + Glib::ustring label[4]; + dCurve->getRangeLabels(label[0], label[1], label[2], label[3]); + double mileStone[3]; + dCurve->getRangeDefaultMilestones(mileStone[0], mileStone[1], mileStone[2]); + paramCurve->setPoints (dCurve->paramCurveEd); + shcSelector->setDefaults(mileStone[0], mileStone[1], mileStone[2]); + shcSelector->setPositions ( + dCurve->paramCurveEd.at(1), + dCurve->paramCurveEd.at(2), + dCurve->paramCurveEd.at(3) + ); + + highlights->setValue (dCurve->paramCurveEd.at(4)); + highlights->setLabel(label[3]); + lights->setValue (dCurve->paramCurveEd.at(5)); + lights->setLabel(label[2]); + darks->setValue (dCurve->paramCurveEd.at(6)); + darks->setLabel(label[1]); + shadows->setValue (dCurve->paramCurveEd.at(7)); + shadows->setLabel(label[0]); + shcSelector->setColorProvider(barColorProvider, dCurve->getBottomBarCallerId()); + shcSelector->setBgGradient(bgGradient); + shcSelector->setMargins( (leftBar ? MyCurve::getBarWidth()+CBAR_MARGIN : RADIUS), RADIUS ); + paramCurve->setColoredBar(leftBar, NULL); + paramCurve->forceResize(); + updateEditButton(dCurve, editParam, editParamConn); + parent->pack_start (*paramCurveBox); + break; + } + case (DCT_NURBS): + NURBSCurve->setPoints (dCurve->NURBSCurveEd); + NURBSCurve->setColorProvider(dCurve->getCurveColorProvider(), dCurve->getCurveCallerId()); + NURBSCurve->setColoredBar(leftBar, bottomBar); + NURBSCurve->forceResize(); + updateEditButton(dCurve, editNURBS, editNURBSConn); + parent->pack_start (*NURBSCurveBox); + NURBSCurveBox->check_resize(); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } + + //dCurve->typeconn.block(false); + } +} + +void DiagonalCurveEditorSubGroup::savePressed () { + + Glib::ustring fname = outputFile(); + if (fname.size()) { + std::ofstream f (fname.c_str()); + std::vector p; + //std::vector p = customCurve->getPoints (); + + switch (parent->displayedCurve->selected) { + case DCT_Spline: // custom + p = customCurve->getPoints (); + break; + case DCT_NURBS: // NURBS + p = NURBSCurve->getPoints (); + break; + case DCT_Parametric: + p = paramCurve->getPoints (); + break; + default: + break; + } + + int ix = 0; + if (p[ix]==(double)(DCT_Linear)) + f << "Linear" << std::endl; + else if (p[ix]==(double)(DCT_Spline)) + f << "Spline" << std::endl; + else if (p[ix]==(double)(DCT_NURBS)) + f << "NURBS" << std::endl; + else if (p[ix]==(double)(DCT_Parametric)) + f << "Parametric" << std::endl; + if (p[ix]==(double)(DCT_Parametric)) { + ix++; + for (unsigned int i=0; i p; + std::string s; + f >> s; + if (s=="Linear") + p.push_back ((double)(DCT_Linear)); + else if (s=="Spline") + p.push_back ((double)(DCT_Spline)); + else if (s=="NURBS") + p.push_back ((double)(DCT_NURBS)); + else if (s=="Parametric") + p.push_back ((double)(DCT_Parametric)); + else return; + + double x; + while (f) { + f >> x; + if (f) + p.push_back (x); + } + if (p[0] == (double)(DCT_Spline)) { + customCurve->setPoints (p); + customCurve->queue_draw (); + customCurve->notifyListener (); + } + else if (p[0] == (double)(DCT_NURBS)) { + NURBSCurve->setPoints (p); + NURBSCurve->queue_draw (); + NURBSCurve->notifyListener (); + } + else if (p[0] == (double)(DCT_Parametric)) { + shcSelector->setPositions ( p[1], p[2], p[3] ); + highlights->setValue (p[4]); + lights->setValue (p[5]); + darks->setValue (p[6]); + shadows->setValue (p[7]); + paramCurve->setPoints (p); + paramCurve->queue_draw (); + paramCurve->notifyListener (); + } + } + } +} + +void DiagonalCurveEditorSubGroup::copyPressed () { +// For compatibility use enum DiagonalCurveType here + + std::vector curve; + + switch (parent->displayedCurve->selected) { + case DCT_Spline: // custom + curve = customCurve->getPoints (); + clipboard.setDiagonalCurveData (curve,DCT_Spline); + break; + case DCT_Parametric: // parametric + // ... do something, first add save/load functions + curve = paramCurve->getPoints (); + clipboard.setDiagonalCurveData (curve,DCT_Parametric); + break; + case DCT_NURBS: // NURBS + curve = NURBSCurve->getPoints (); + clipboard.setDiagonalCurveData (curve,DCT_NURBS); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +void DiagonalCurveEditorSubGroup::pastePressed () { +// For compatibility use enum DiagonalCurveType here + + std::vector curve; + DiagonalCurveType type; + + type = clipboard.hasDiagonalCurveData(); + + if (type == (DiagonalCurveType)parent->displayedCurve->selected) { + curve = clipboard.getDiagonalCurveData (); + switch (type) { + case DCT_Spline: // custom + customCurve->setPoints (curve); + customCurve->queue_draw (); + customCurve->notifyListener (); + break; + case DCT_Parametric: // parametric + // ... do something, first add save/load functions + shcSelector->setPositions ( + curve[1], + curve[2], + curve[3] ); + highlights->setValue (curve[4]); + lights->setValue (curve[5]); + darks->setValue (curve[6]); + shadows->setValue (curve[7]); + paramCurve->setPoints (curve); + paramCurve->queue_draw (); + paramCurve->notifyListener (); + break; + case DCT_NURBS: // NURBS + NURBSCurve->setPoints (curve); + NURBSCurve->queue_draw (); + NURBSCurve->notifyListener (); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } + } + return; +} + +void DiagonalCurveEditorSubGroup::editPointToggled(Gtk::ToggleButton *button) { + if (button->get_active()) { + customCoordAdjuster->show(); + NURBSCoordAdjuster->show(); + } + else { + if (customCoordAdjuster) { + customCurve->stopNumericalAdjustment(); + customCoordAdjuster->hide(); + NURBSCurve->stopNumericalAdjustment(); + NURBSCoordAdjuster->hide(); + } + } + if (button == editPointCustom) { + editPointNURBSConn.block(true); + editPointNURBS->set_active(!editPointNURBS->get_active()); + editPointNURBSConn.block(false); + } + else { + editPointCustomConn.block(true); + editPointCustom->set_active(!editPointCustom->get_active()); + editPointCustomConn.block(false); + } +} + +void DiagonalCurveEditorSubGroup::editToggled (Gtk::ToggleButton *button) { + DiagonalCurveEditor* dCurve = static_cast(parent->displayedCurve); + if (!dCurve) + // should never happen! + return; + + if (button->get_active()) { + dCurve->subscribe(); + if (button == editCustom) + customCurve->notifyListener (); + else if (button == editNURBS) + NURBSCurve->notifyListener (); + else if (button == editParam) + paramCurve->notifyListener (); + + /* + if (button != editCustom) { + editCustomConn.block(true); + editCustom->set_active(true); + editCustomConn.block(false); + } + else { + // will throw the event of curveChanged, which will now build the edit's buffer + customCurve->notifyListener (); + } + if (button != editNURBS) { + editNURBSConn.block(true); + editNURBS->set_active(true); + editNURBSConn.block(false); + } + else { + NURBSCurve->notifyListener (); + } + if (button != editParam) { + editParamConn.block(true); + editParam->set_active(true); + editParamConn.block(false); + } + else { + paramCurve->notifyListener (); + } + */ + } + else { + dCurve->unsubscribe(); + /* + if (button != editCustom ) { editCustomConn.block(true); editCustom->set_active(false); editCustomConn.block(false); } + if (button != editNURBS ) { editNURBSConn.block(true); editNURBS->set_active(false); editNURBSConn.block(false); } + if (button != editParam ) { editParamConn.block(true); editParam->set_active(false); editParamConn.block(false); } + */ + } +} + +/* + * Store the curves of the currently displayed type from the widgets to the CurveEditor object + */ +void DiagonalCurveEditorSubGroup::storeDisplayedCurve() { + if (parent->displayedCurve) { + switch (parent->displayedCurve->selected) { + case (DCT_Spline): + storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_Spline)); + break; + case (DCT_Parametric): + storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_Parametric)); + break; + case (DCT_NURBS): + storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_NURBS)); + break; + default: + break; + } + } +} + +/* + * Restore the histogram to all types from the CurveEditor object to the widgets + */ +void DiagonalCurveEditorSubGroup::restoreDisplayedHistogram() { + if (parent->displayedCurve /*&& initslope==1*/) { + paramCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); + customCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); + NURBSCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); + } + +} + +void DiagonalCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::vector& p) { + if (!p.empty()) { + DiagonalCurveType t = (DiagonalCurveType)p[0]; + + switch (t) { + case (DCT_Spline): + (static_cast(ce))->customCurveEd = p; + break; + case (DCT_Parametric): + (static_cast(ce))->paramCurveEd = p; + break; + case (DCT_NURBS): + (static_cast(ce))->NURBSCurveEd = p; + break; + default: + break; + } + } +} + +/* + * Called to update the parametric curve graph with new slider values + */ +const std::vector DiagonalCurveEditorSubGroup::getCurveFromGUI (int type) { + switch ((DiagonalCurveType)type) { + case (DCT_Parametric): { + std::vector lcurve (8); + lcurve[0] = (double)(DCT_Parametric); + shcSelector->getPositions (lcurve[1], lcurve[2], lcurve[3]); + lcurve[4] = highlights->getValue (); + lcurve[5] = lights->getValue (); + lcurve[6] = darks->getValue (); + lcurve[7] = shadows->getValue (); + return lcurve; + } + case (DCT_Spline): + return customCurve->getPoints (); + case (DCT_NURBS): + return NURBSCurve->getPoints (); + default: { + // linear and other solutions + std::vector lcurve (1); + lcurve[0] = (double)(DCT_Linear); + return lcurve; + } + } +} + +/* + * Unlink the tree editor widgets from their parent box to hide them + */ +void DiagonalCurveEditorSubGroup::removeEditor () { + removeIfThere (parent, customCurveBox, false); + removeIfThere (parent, paramCurveBox, false); + removeIfThere (parent, NURBSCurveBox, false); +} + +bool DiagonalCurveEditorSubGroup::curveReset(CurveEditor *ce) { + if (!ce) + return false; + + DiagonalCurveEditor *dce = static_cast(ce); + + switch (ce->selected) { + case (DCT_NURBS) : // = Control cage + NURBSCurve->reset (dce->NURBSResetCurve, dce->getIdentityValue()); + return true; + break; + case (DCT_Spline) : // = Custom + customCurve->reset (dce->customResetCurve, dce->getIdentityValue()); + return true; + break; + case (DCT_Parametric) : + { + DiagonalCurveEditor* dCurve = static_cast(parent->displayedCurve); + double mileStone[3]; + dCurve->getRangeDefaultMilestones(mileStone[0], mileStone[1], mileStone[2]); + + highlights->resetPressed(NULL); + lights->resetPressed(NULL); + darks->resetPressed(NULL); + shadows->resetPressed(NULL); + shcSelector->setDefaults(mileStone[0], mileStone[1], mileStone[2]); + shcSelector->reset(); + paramCurve->reset (dce->paramResetCurve, dce->getIdentityValue()); + return true; + break; + } + default: + return false; + break; + } + return true; +} + +/* + * Listener + */ +void DiagonalCurveEditorSubGroup::shcChanged () { + + paramCurve->setPoints (getCurveFromGUI(DCT_Parametric)); + storeDisplayedCurve(); + parent->curveChanged (); +} + +/* + * Listener + */ +void DiagonalCurveEditorSubGroup::adjusterChanged (Adjuster* a, double newval) { + + paramCurve->setPoints (getCurveFromGUI(DCT_Parametric)); + storeDisplayedCurve(); + parent->curveChanged (); +} + +/* + * Listener called when the mouse is over a parametric curve's slider + */ +bool DiagonalCurveEditorSubGroup::adjusterEntered (GdkEventCrossing* ev, int ac) { + + if (ev->detail != GDK_NOTIFY_INFERIOR) { + activeParamControl = ac; + paramCurve->setActiveParam (activeParamControl); + } + return true; +} + +/* + * Listener called when the mouse left the parametric curve's slider + */ +bool DiagonalCurveEditorSubGroup::adjusterLeft (GdkEventCrossing* ev, int ac) { + + if (ev->detail != GDK_NOTIFY_INFERIOR) { + activeParamControl = -1; + paramCurve->setActiveParam (activeParamControl); + } + return true; +} + +void DiagonalCurveEditorSubGroup::updateBackgroundHistogram (CurveEditor* ce) { + if (ce==parent->displayedCurve /*&& initslope==1*/) { + paramCurve->updateBackgroundHistogram (ce->histogram); + customCurve->updateBackgroundHistogram (ce->histogram); + NURBSCurve->updateBackgroundHistogram (ce->histogram); + } +} + +void DiagonalCurveEditorSubGroup::setSubGroupRangeLabels(Glib::ustring r1, Glib::ustring r2, Glib::ustring r3, Glib::ustring r4) { + shadows->setLabel(r1); + darks->setLabel(r2); + lights->setLabel(r3); + highlights->setLabel(r4); +} diff --git a/rtgui/diagonalcurveeditorsubgroup.h b/rtgui/diagonalcurveeditorsubgroup.h index e10daf3ed..827cebac3 100644 --- a/rtgui/diagonalcurveeditorsubgroup.h +++ b/rtgui/diagonalcurveeditorsubgroup.h @@ -1,113 +1,113 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _DIAGONALCURVEEDITORSUBGROUP_ -#define _DIAGONALCURVEEDITORSUBGROUP_ - -#include -#include "curveeditorgroup.h" - -class DiagonalCurveEditor; - -class DiagonalCurveEditorSubGroup : public CurveEditorSubGroup, public SHCListener, public AdjusterListener { - - friend class DiagonalCurveEditor; - -protected: - Gtk::VBox* customCurveBox; - Gtk::VBox* NURBSCurveBox; - Gtk::VBox* paramCurveBox; - - MyDiagonalCurve* customCurve; - MyDiagonalCurve* NURBSCurve; - MyDiagonalCurve* paramCurve; - - SHCSelector* shcSelector; - Adjuster* highlights; - Adjuster* lights; - Adjuster* darks; - Adjuster* shadows; - - Adjuster *editedAdjuster; - int editedAdjusterValue; - - CoordinateAdjuster *customCoordAdjuster; - CoordinateAdjuster *NURBSCoordAdjuster; - - Gtk::Button* saveCustom; - Gtk::Button* loadCustom; - Gtk::Button* copyCustom; - Gtk::Button* pasteCustom; - Gtk::ToggleButton* editPointCustom; - Gtk::ToggleButton* editCustom; - sigc::connection editCustomConn, editPointCustomConn; - Gtk::Button* saveNURBS; - Gtk::Button* loadNURBS; - Gtk::Button* copyNURBS; - Gtk::Button* pasteNURBS; - Gtk::ToggleButton* editPointNURBS; - Gtk::ToggleButton* editNURBS; - sigc::connection editNURBSConn, editPointNURBSConn; - Gtk::Button* saveParam; - Gtk::Button* loadParam; - Gtk::Button* copyParam; - Gtk::Button* pasteParam; - Gtk::ToggleButton* editParam; - sigc::connection editParamConn; - - int activeParamControl; - -public: - DiagonalCurveEditorSubGroup(CurveEditorGroup* prt, Glib::ustring& curveDir); - virtual ~DiagonalCurveEditorSubGroup(); - - DiagonalCurveEditor* addCurve(Glib::ustring curveLabel = ""); - virtual void updateBackgroundHistogram (CurveEditor* ce); - void switchGUI(); - void refresh(CurveEditor *curveToRefresh); - void editModeSwitchedOff (); - void pipetteMouseOver(EditDataProvider *provider, int modifierKey); - void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey); - void pipetteButton1Released(EditDataProvider *provider); - void pipetteDrag(EditDataProvider *provider, int modifierKey); - void showCoordinateAdjuster(CoordinateProvider *provider); - void stopNumericalAdjustment(); - - bool curveReset (CurveEditor *ce); - -protected: - void storeCurveValues (CurveEditor* ce, const std::vector& p); - void storeDisplayedCurve (); - void restoreDisplayedHistogram (); - void savePressed (); - void loadPressed (); - void copyPressed (); - void pastePressed (); - void editPointToggled(Gtk::ToggleButton *button); - void editToggled (Gtk::ToggleButton *button); - void removeEditor (); - const std::vector getCurveFromGUI (int type); - void shcChanged (); - void adjusterChanged (Adjuster* a, double newval); - bool adjusterEntered (GdkEventCrossing* ev, int ac); - bool adjusterLeft (GdkEventCrossing* ev, int ac); - void setSubGroupRangeLabels(Glib::ustring r1, Glib::ustring r2, Glib::ustring r3, Glib::ustring r4); - void setSubGroupBottomBarBgGradient(); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _DIAGONALCURVEEDITORSUBGROUP_ +#define _DIAGONALCURVEEDITORSUBGROUP_ + +#include +#include "curveeditorgroup.h" + +class DiagonalCurveEditor; + +class DiagonalCurveEditorSubGroup : public CurveEditorSubGroup, public SHCListener, public AdjusterListener { + + friend class DiagonalCurveEditor; + +protected: + Gtk::VBox* customCurveBox; + Gtk::VBox* NURBSCurveBox; + Gtk::VBox* paramCurveBox; + + MyDiagonalCurve* customCurve; + MyDiagonalCurve* NURBSCurve; + MyDiagonalCurve* paramCurve; + + SHCSelector* shcSelector; + Adjuster* highlights; + Adjuster* lights; + Adjuster* darks; + Adjuster* shadows; + + Adjuster *editedAdjuster; + int editedAdjusterValue; + + CoordinateAdjuster *customCoordAdjuster; + CoordinateAdjuster *NURBSCoordAdjuster; + + Gtk::Button* saveCustom; + Gtk::Button* loadCustom; + Gtk::Button* copyCustom; + Gtk::Button* pasteCustom; + Gtk::ToggleButton* editPointCustom; + Gtk::ToggleButton* editCustom; + sigc::connection editCustomConn, editPointCustomConn; + Gtk::Button* saveNURBS; + Gtk::Button* loadNURBS; + Gtk::Button* copyNURBS; + Gtk::Button* pasteNURBS; + Gtk::ToggleButton* editPointNURBS; + Gtk::ToggleButton* editNURBS; + sigc::connection editNURBSConn, editPointNURBSConn; + Gtk::Button* saveParam; + Gtk::Button* loadParam; + Gtk::Button* copyParam; + Gtk::Button* pasteParam; + Gtk::ToggleButton* editParam; + sigc::connection editParamConn; + + int activeParamControl; + +public: + DiagonalCurveEditorSubGroup(CurveEditorGroup* prt, Glib::ustring& curveDir); + virtual ~DiagonalCurveEditorSubGroup(); + + DiagonalCurveEditor* addCurve(Glib::ustring curveLabel = ""); + virtual void updateBackgroundHistogram (CurveEditor* ce); + void switchGUI(); + void refresh(CurveEditor *curveToRefresh); + void editModeSwitchedOff (); + void pipetteMouseOver(EditDataProvider *provider, int modifierKey); + void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey); + void pipetteButton1Released(EditDataProvider *provider); + void pipetteDrag(EditDataProvider *provider, int modifierKey); + void showCoordinateAdjuster(CoordinateProvider *provider); + void stopNumericalAdjustment(); + + bool curveReset (CurveEditor *ce); + +protected: + void storeCurveValues (CurveEditor* ce, const std::vector& p); + void storeDisplayedCurve (); + void restoreDisplayedHistogram (); + void savePressed (); + void loadPressed (); + void copyPressed (); + void pastePressed (); + void editPointToggled(Gtk::ToggleButton *button); + void editToggled (Gtk::ToggleButton *button); + void removeEditor (); + const std::vector getCurveFromGUI (int type); + void shcChanged (); + void adjusterChanged (Adjuster* a, double newval); + bool adjusterEntered (GdkEventCrossing* ev, int ac); + bool adjusterLeft (GdkEventCrossing* ev, int ac); + void setSubGroupRangeLabels(Glib::ustring r1, Glib::ustring r2, Glib::ustring r3, Glib::ustring r4); + void setSubGroupBottomBarBgGradient(); +}; + +#endif diff --git a/rtgui/distortion.cc b/rtgui/distortion.cc index 79116c7e1..50795bbab 100644 --- a/rtgui/distortion.cc +++ b/rtgui/distortion.cc @@ -1,112 +1,112 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "distortion.h" -#include -#include "rtimage.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -Distortion::Distortion (): FoldableToolPanel(this, "distortion", M("TP_DISTORTION_LABEL")) { - - rlistener = NULL; - autoDistor = Gtk::manage (new Gtk::Button (M("TP_DISTORTION_AUTO"))); - autoDistor->set_image (*Gtk::manage (new RTImage ("distortion-auto.png"))); - autoDistor->set_tooltip_text (M("TP_DISTORTION_AUTO_TIP")); - idConn = autoDistor->signal_pressed().connect( sigc::mem_fun(*this, &Distortion::idPressed) ); - autoDistor->show(); - pack_start (*autoDistor); - - Gtk::Image* idistL = Gtk::manage (new RTImage ("distortion-pincushion.png")); - Gtk::Image* idistR = Gtk::manage (new RTImage ("distortion-barrel.png")); - - distor = Gtk::manage (new Adjuster (M("TP_DISTORTION_AMOUNT"), -0.5, 0.5, 0.001, 0, idistL, idistR)); - distor->setAdjusterListener (this); - distor->show(); - pack_start (*distor); -} - -void Distortion::read (const ProcParams* pp, const ParamsEdited* pedited) { - - disableListener (); - - if (pedited) { - distor->setEditedState (pedited->distortion.amount ? Edited : UnEdited); - } - - distor->setValue (pp->distortion.amount); - - enableListener (); -} - -void Distortion::write (ProcParams* pp, ParamsEdited* pedited) { - - pp->distortion.amount = distor->getValue (); - - if (pedited) { - pedited->distortion.amount = distor->getEditedState (); - } -} - -void Distortion::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - - distor->setDefault (defParams->distortion.amount); - - if (pedited) { - distor->setDefaultEditedState (pedited->distortion.amount ? Edited : UnEdited); - } - else { - distor->setDefaultEditedState (Irrelevant); - } -} - -void Distortion::adjusterChanged (Adjuster* a, double newval) { - - if (listener) - listener->panelChanged (EvDISTAmount, Glib::ustring::format (std::setw(4), std::fixed, std::setprecision(3), a->getValue())); -} - -void Distortion::setBatchMode (bool batchMode) { - - ToolPanel::setBatchMode (batchMode); - if (batchMode) { - autoDistor->set_sensitive(false); - } - distor->showEditedCB (); -} - -void Distortion::idPressed () { - if (!batchMode) { - if (rlistener) { - double new_amount = rlistener->autoDistorRequested(); - distor->setValue(new_amount); - adjusterChanged (distor, new_amount); - } - } -} - -void Distortion::setAdjusterBehavior (bool vadd) { - - distor->setAddMode(vadd); -} - -void Distortion::trimValues (rtengine::procparams::ProcParams* pp) { - - distor->trimValue(pp->distortion.amount); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "distortion.h" +#include +#include "rtimage.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +Distortion::Distortion (): FoldableToolPanel(this, "distortion", M("TP_DISTORTION_LABEL")) { + + rlistener = NULL; + autoDistor = Gtk::manage (new Gtk::Button (M("TP_DISTORTION_AUTO"))); + autoDistor->set_image (*Gtk::manage (new RTImage ("distortion-auto.png"))); + autoDistor->set_tooltip_text (M("TP_DISTORTION_AUTO_TIP")); + idConn = autoDistor->signal_pressed().connect( sigc::mem_fun(*this, &Distortion::idPressed) ); + autoDistor->show(); + pack_start (*autoDistor); + + Gtk::Image* idistL = Gtk::manage (new RTImage ("distortion-pincushion.png")); + Gtk::Image* idistR = Gtk::manage (new RTImage ("distortion-barrel.png")); + + distor = Gtk::manage (new Adjuster (M("TP_DISTORTION_AMOUNT"), -0.5, 0.5, 0.001, 0, idistL, idistR)); + distor->setAdjusterListener (this); + distor->show(); + pack_start (*distor); +} + +void Distortion::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + distor->setEditedState (pedited->distortion.amount ? Edited : UnEdited); + } + + distor->setValue (pp->distortion.amount); + + enableListener (); +} + +void Distortion::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->distortion.amount = distor->getValue (); + + if (pedited) { + pedited->distortion.amount = distor->getEditedState (); + } +} + +void Distortion::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + distor->setDefault (defParams->distortion.amount); + + if (pedited) { + distor->setDefaultEditedState (pedited->distortion.amount ? Edited : UnEdited); + } + else { + distor->setDefaultEditedState (Irrelevant); + } +} + +void Distortion::adjusterChanged (Adjuster* a, double newval) { + + if (listener) + listener->panelChanged (EvDISTAmount, Glib::ustring::format (std::setw(4), std::fixed, std::setprecision(3), a->getValue())); +} + +void Distortion::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + if (batchMode) { + autoDistor->set_sensitive(false); + } + distor->showEditedCB (); +} + +void Distortion::idPressed () { + if (!batchMode) { + if (rlistener) { + double new_amount = rlistener->autoDistorRequested(); + distor->setValue(new_amount); + adjusterChanged (distor, new_amount); + } + } +} + +void Distortion::setAdjusterBehavior (bool vadd) { + + distor->setAddMode(vadd); +} + +void Distortion::trimValues (rtengine::procparams::ProcParams* pp) { + + distor->trimValue(pp->distortion.amount); +} diff --git a/rtgui/distortion.h b/rtgui/distortion.h index 447c3c692..ecaa2b4e7 100644 --- a/rtgui/distortion.h +++ b/rtgui/distortion.h @@ -1,51 +1,51 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _DISTORTION_H_ -#define _DISTORTION_H_ - -#include -#include "adjuster.h" -#include "toolpanel.h" -#include "lensgeomlistener.h" - -class Distortion : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { - - protected: - Gtk::Button* autoDistor; - Adjuster* distor; - sigc::connection idConn; - LensGeomListener * rlistener; - - public: - - Distortion (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - - void adjusterChanged (Adjuster* a, double newval); - void setAdjusterBehavior (bool vadd); - void trimValues (rtengine::procparams::ProcParams* pp); - void idPressed (); - void setLensGeomListener (LensGeomListener* l) { rlistener = l; } -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _DISTORTION_H_ +#define _DISTORTION_H_ + +#include +#include "adjuster.h" +#include "toolpanel.h" +#include "lensgeomlistener.h" + +class Distortion : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { + + protected: + Gtk::Button* autoDistor; + Adjuster* distor; + sigc::connection idConn; + LensGeomListener * rlistener; + + public: + + Distortion (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void setAdjusterBehavior (bool vadd); + void trimValues (rtengine::procparams::ProcParams* pp); + void idPressed (); + void setLensGeomListener (LensGeomListener* l) { rlistener = l; } +}; + +#endif diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index c8248ace3..ed513c74e 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1,1656 +1,1656 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * Copyright (c) 2010 Oliver Duis - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "editorpanel.h" -#include "options.h" -#include "progressconnector.h" -#include "rtwindow.h" -#include "guiutils.h" -#include "procparamchangers.h" -#include "../rtengine/safegtk.h" -#include "../rtengine/imagesource.h" -#include "soundman.h" -#include "rtimage.h" -#include - -using namespace rtengine::procparams; - -EditorPanel::EditorPanel (FilePanel* filePanel) - : realized(false), iHistoryShow(NULL), iHistoryHide(NULL), iTopPanel_1_Show(NULL), iTopPanel_1_Hide(NULL), iRightPanel_1_Show(NULL), iRightPanel_1_Hide(NULL), iBeforeLockON(NULL),iBeforeLockOFF(NULL), beforePreviewHandler(NULL), beforeIarea(NULL), beforeBox(NULL), afterBox(NULL), afterHeaderBox(NULL), parent(NULL), openThm(NULL), ipc(NULL), beforeIpc(NULL), isProcessing(false), catalogPane(NULL) { - - epih = new EditorPanelIdleHelper; - epih->epanel = this; - epih->destroyed = false; - epih->pending = 0; - //rtengine::befaf=true; - processingStartedTime = 0; - firstProcessingDone = false; - - // construct toolpanelcoordinator - tpc = new ToolPanelCoordinator (); - - // build GUI - - // build left side panel - leftbox = new Gtk::VBox (); - leftbox->set_border_width (2); - leftbox->set_size_request(100,250); - - histogramPanel = NULL; - - profilep = Gtk::manage (new ProfilePanel ()); - ppframe = new Gtk::Frame (); - ppframe->add (*profilep); - ppframe->set_label (M("PROFILEPANEL_LABEL")); - //leftbox->pack_start (*ppframe, Gtk::PACK_SHRINK, 4); - - navigator = Gtk::manage (new Navigator ()); - navigator->previewWindow->set_size_request (-1, 150); - leftbox->pack_start (*navigator, Gtk::PACK_SHRINK, 2); - - history = Gtk::manage (new History ()); - leftbox->pack_start (*history); - - leftbox->show_all (); - - // build the middle of the screen - Gtk::VBox* editbox = Gtk::manage (new Gtk::VBox ()); - - info = Gtk::manage (new Gtk::ToggleButton ()); - Gtk::Image* infoimg = Gtk::manage (new RTImage ("info.png")); - info->add (*infoimg); - info->set_relief(Gtk::RELIEF_NONE); - info->set_tooltip_markup (M("MAIN_TOOLTIP_QINFO")); - - beforeAfter = Gtk::manage (new Gtk::ToggleButton ()); - Gtk::Image* beforeAfterIcon = Gtk::manage (new RTImage ("beforeafter.png")); - beforeAfter->add(*beforeAfterIcon); - beforeAfter->set_relief(Gtk::RELIEF_NONE); - beforeAfter->set_tooltip_markup (M("MAIN_TOOLTIP_TOGGLE")); - - iBeforeLockON = new RTImage ("lock-on.png"); - iBeforeLockOFF = new RTImage ("lock-off.png"); - - Gtk::VSeparator* vsept = Gtk::manage (new Gtk::VSeparator ()); - Gtk::VSeparator* vsepz = Gtk::manage (new Gtk::VSeparator ()); - Gtk::VSeparator* vsepi = Gtk::manage (new Gtk::VSeparator ()); - Gtk::VSeparator* vseph = Gtk::manage (new Gtk::VSeparator ()); - - hidehp = Gtk::manage (new Gtk::ToggleButton ()); - - iHistoryShow = new RTImage ("panel-to-right.png"); - iHistoryHide = new RTImage ("panel-to-left.png"); - - hidehp->set_relief(Gtk::RELIEF_NONE); - hidehp->set_active (options.showHistory); - hidehp->set_tooltip_markup (M("MAIN_TOOLTIP_HIDEHP")); - if (options.showHistory){ - hidehp->set_image (*iHistoryHide); - } - else { - hidehp->set_image (*iHistoryShow); - } - - tbTopPanel_1 = NULL; - if (!simpleEditor && filePanel) { - tbTopPanel_1 = new Gtk::ToggleButton (); - iTopPanel_1_Show = new RTImage ("panel-to-bottom.png"); - iTopPanel_1_Hide = new RTImage ("panel-to-top.png"); - tbTopPanel_1->set_relief(Gtk::RELIEF_NONE); - tbTopPanel_1->set_active (true); - tbTopPanel_1->set_tooltip_markup (M("MAIN_TOOLTIP_SHOWHIDETP1")); - tbTopPanel_1->set_image (*iTopPanel_1_Hide); - } - - tbRightPanel_1 = new Gtk::ToggleButton (); - iRightPanel_1_Show = new RTImage ("panel-to-left.png"); - iRightPanel_1_Hide = new RTImage ("panel-to-right.png"); - tbRightPanel_1->set_relief(Gtk::RELIEF_NONE); - tbRightPanel_1->set_active (true); - tbRightPanel_1->set_tooltip_markup (M("MAIN_TOOLTIP_SHOWHIDERP1")); - tbRightPanel_1->set_image (*iRightPanel_1_Hide); - - Gtk::VSeparator* vsepcl = Gtk::manage (new Gtk::VSeparator ()); - Gtk::VSeparator* vsepz2 = Gtk::manage (new Gtk::VSeparator ()); - Gtk::VSeparator* vsepz3 = Gtk::manage (new Gtk::VSeparator ()); - Gtk::VSeparator* vsepz4 = Gtk::manage (new Gtk::VSeparator ()); - - iareapanel = new ImageAreaPanel (); - tpc->setEditProvider(iareapanel->imageArea); - - Gtk::HBox* toolBarPanel = Gtk::manage (new Gtk::HBox ()); - toolBarPanel->pack_start (*hidehp, Gtk::PACK_SHRINK, 1); - toolBarPanel->pack_start (*vseph, Gtk::PACK_SHRINK, 2); - toolBarPanel->pack_start (*info, Gtk::PACK_SHRINK, 1); - toolBarPanel->pack_start (*beforeAfter, Gtk::PACK_SHRINK, 1); - toolBarPanel->pack_start (*vsepi, Gtk::PACK_SHRINK, 2); - toolBarPanel->pack_start (*tpc->getToolBar(), Gtk::PACK_SHRINK, 1); - toolBarPanel->pack_start (*vsept, Gtk::PACK_SHRINK, 2); - - if (tbTopPanel_1) { - toolBarPanel->pack_end (*tbTopPanel_1, Gtk::PACK_SHRINK, 1); - Gtk::VSeparator* vsep1 = Gtk::manage (new Gtk::VSeparator ()); - toolBarPanel->pack_end (*vsep1, Gtk::PACK_SHRINK, 2); - } - toolBarPanel->pack_end (*tpc->coarse, Gtk::PACK_SHRINK, 2); - toolBarPanel->pack_end (*vsepcl, Gtk::PACK_SHRINK, 2); - toolBarPanel->pack_end (*iareapanel->imageArea->indClippedPanel, Gtk::PACK_SHRINK, 0); - toolBarPanel->pack_end (*vsepz, Gtk::PACK_SHRINK, 2); - toolBarPanel->pack_end (*iareapanel->imageArea->previewModePanel, Gtk::PACK_SHRINK, 0); - toolBarPanel->pack_end (*vsepz4, Gtk::PACK_SHRINK, 2); - - afterBox = Gtk::manage (new Gtk::VBox ()); - afterBox->pack_start (*iareapanel); - - beforeAfterBox = Gtk::manage (new Gtk::HBox()); - beforeAfterBox->pack_start (*afterBox); - - editbox->pack_start (*toolBarPanel, Gtk::PACK_SHRINK,0); - editbox->pack_start (*beforeAfterBox); - - // build right side panel - vboxright = new Gtk::VBox (false, 0); - vboxright->set_size_request(100,250); - - vboxright->set_border_width (2); - - vboxright->pack_start (*ppframe, Gtk::PACK_SHRINK, 2); - // main notebook - vboxright->pack_start (*tpc->toolPanelNotebook); - - // Save buttons - Gtk::HBox* iops = Gtk::manage (new Gtk::HBox ()); - - //Gtk::Image *saveButtonImage = Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)); - Gtk::Image *saveButtonImage = Gtk::manage (new RTImage ("gtk-save-large.png")); - saveimgas = Gtk::manage (new Gtk::Button ()); - saveimgas->add(*saveButtonImage); - saveimgas->set_tooltip_markup(M("MAIN_BUTTON_SAVE_TOOLTIP")); - - Gtk::Image *queueButtonImage = Gtk::manage (new RTImage ("processing.png")); - queueimg = Gtk::manage (new Gtk::Button ()); - queueimg->add(*queueButtonImage); - queueimg->set_tooltip_markup(M("MAIN_BUTTON_PUTTOQUEUE_TOOLTIP")); - - Gtk::Image *sendToEditorButtonImage = Gtk::manage (new RTImage ("image-editor.png")); - sendtogimp = Gtk::manage (new Gtk::Button ()); - sendtogimp->add(*sendToEditorButtonImage); - sendtogimp->set_tooltip_markup(M("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP")); - - iops->pack_start (*saveimgas, Gtk::PACK_SHRINK); - if(!simpleEditor) - iops->pack_start (*queueimg, Gtk::PACK_SHRINK); - iops->pack_start (*sendtogimp, Gtk::PACK_SHRINK); - - // Status box - statusBox = Gtk::manage (new Gtk::HBox ()); - progressLabel = Gtk::manage (new Gtk::ProgressBar()); - progressLabel->set_fraction(0.0); - //progressLabel->modify_bg( Gtk::STATE_NORMAL,Gdk::Color("grey") ); // Disable, because in single mode this is may be permanent red without processing - - statusBox->pack_start (*progressLabel); - iops->pack_start(*statusBox, Gtk::PACK_SHRINK, 2); - - // tbRightPanel_1 - iops->pack_end (*tbRightPanel_1, Gtk::PACK_SHRINK,0); - - // ShowHideSidePanels - tbShowHideSidePanels = new Gtk::ToggleButton (); - iShowHideSidePanels = new RTImage ("crossed-arrows-out.png"); - iShowHideSidePanels_exit = new RTImage ("crossed-arrows-in.png"); - tbShowHideSidePanels->set_relief(Gtk::RELIEF_NONE); - tbShowHideSidePanels->set_active (false); - tbShowHideSidePanels->set_tooltip_markup (M("MAIN_BUTTON_SHOWHIDESIDEPANELS_TOOLTIP")); - tbShowHideSidePanels->set_image (*iShowHideSidePanels); - iops->pack_end (*tbShowHideSidePanels, Gtk::PACK_SHRINK,0); - iops->pack_end (*vsepz2, Gtk::PACK_SHRINK,1); - - // Zoom panel - iops->pack_end (*iareapanel->imageArea->zoomPanel, Gtk::PACK_SHRINK, 1); - iops->pack_end (*vsepz3, Gtk::PACK_SHRINK, 2); - - navPrev = navNext = navSync = NULL; - if (!simpleEditor && !options.tabbedUI){ - // Navigation buttons - Gtk::Image *navPrevImage = Gtk::manage (new RTImage ("nav-prev.png")); - navPrevImage->set_padding(0,0); - navPrev = Gtk::manage (new Gtk::Button ()); - navPrev->add(*navPrevImage); - navPrev->set_relief(Gtk::RELIEF_NONE); - navPrev->set_tooltip_markup(M("MAIN_BUTTON_NAVPREV_TOOLTIP")); - - Gtk::Image *navNextImage = Gtk::manage (new RTImage ("nav-next.png")); - navNextImage->set_padding(0,0); - navNext = Gtk::manage (new Gtk::Button ()); - navNext->add(*navNextImage); - navNext->set_relief(Gtk::RELIEF_NONE); - navNext->set_tooltip_markup(M("MAIN_BUTTON_NAVNEXT_TOOLTIP")); - - Gtk::Image *navSyncImage = Gtk::manage (new RTImage ("nav-sync.png")); - navSyncImage->set_padding(0,0); - navSync = Gtk::manage (new Gtk::Button ()); - navSync->add(*navSyncImage); - navSync->set_relief(Gtk::RELIEF_NONE); - navSync->set_tooltip_markup(M("MAIN_BUTTON_NAVSYNC_TOOLTIP")); - - iops->pack_end (*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_SHRINK, 0); - iops->pack_end (*navNext, Gtk::PACK_SHRINK, 0); - iops->pack_end (*navSync, Gtk::PACK_SHRINK, 0); - iops->pack_end (*navPrev, Gtk::PACK_SHRINK, 0); - } - - editbox->pack_start (*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0); - editbox->pack_start (*iops, Gtk::PACK_SHRINK, 0); - editbox->show_all (); - - // build screen - hpanedl = Gtk::manage (new Gtk::HPaned()); - hpanedr = Gtk::manage (new Gtk::HPaned()); - leftbox->reference (); - vboxright->reference (); - if (options.showHistory) { - hpanedl->pack1(*leftbox, false, true); - hpanedl->set_position (options.historyPanelWidth); - } - - - Gtk::VPaned * viewpaned = Gtk::manage (new Gtk::VPaned()); - fPanel = filePanel; - if(filePanel) - { - catalogPane = new Gtk::Paned(); - viewpaned->pack1(*catalogPane, false, true); - } - viewpaned->pack2(*editbox, true, true); - - - Gtk::Frame* vbfr = Gtk::manage (new Gtk::Frame ()); - vbfr->add (*viewpaned); - vbfr->set_size_request(100,250); - hpanedl->pack2(*vbfr, true, true); - - hpanedr->pack1(*hpanedl, true, true); - hpanedr->pack2(*vboxright, false, true); - hpanedl->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &EditorPanel::leftPaneButtonReleased) ); - hpanedr->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &EditorPanel::rightPaneButtonReleased) ); - - pack_start (*hpanedr); - - updateHistogramPosition (0, options.histogramPosition); - - show_all (); -/* - // save as dialog - if (safe_file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR)) - saveAsDialog = new SaveAsDialog (options.lastSaveAsPath); - else - saveAsDialog = new SaveAsDialog (safe_get_user_picture_dir()); - - saveAsDialog->set_default_size (options.saveAsDialogWidth, options.saveAsDialogHeight); -*/ - // connect listeners - profilep->setProfileChangeListener (tpc); - history->setProfileChangeListener (tpc); - history->setHistoryBeforeLineListener (this); - tpc->addPParamsChangeListener (profilep); - tpc->addPParamsChangeListener (history); - tpc->addPParamsChangeListener (this); - iareapanel->imageArea->setCropGUIListener (tpc->getCropGUIListener()); - iareapanel->imageArea->setPointerMotionListener (navigator); - iareapanel->imageArea->setImageAreaToolListener (tpc); - - // initialize components - info->set_active (options.showInfo); - tpc->readOptions (); - - // connect event handlers - info->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::info_toggled) ); - beforeAfter->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::beforeAfterToggled) ); - hidehp->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::hideHistoryActivated) ); - tbRightPanel_1->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::tbRightPanel_1_toggled) ); - saveimgas->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::saveAsPressed) ); - queueimg->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::queueImgPressed) ); - sendtogimp->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::sendToGimpPressed) ); - if(navPrev) - navPrev->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::openPreviousEditorImage) ); - if(navNext) - navNext->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::openNextEditorImage) ); - if(navSync) - navSync->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::syncFileBrowser) ); - ShowHideSidePanelsconn = tbShowHideSidePanels->signal_toggled().connect ( sigc::mem_fun(*this, &EditorPanel::toggleSidePanels), true); - if (tbTopPanel_1) - tbTopPanel_1->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::tbTopPanel_1_toggled) ); -} - -EditorPanel::~EditorPanel () { - - history->setHistoryBeforeLineListener (NULL); - // the order is important! - iareapanel->setBeforeAfterViews (NULL, iareapanel); - delete iareapanel; - iareapanel = NULL; - - if (beforeIpc) - beforeIpc->stopProcessing (); - - delete beforeIarea; - beforeIarea = NULL; - - if (beforeIpc){ - beforeIpc->setPreviewImageListener (NULL); - } - delete beforePreviewHandler; - beforePreviewHandler = NULL; - if (beforeIpc) - rtengine::StagedImageProcessor::destroy (beforeIpc); - beforeIpc = NULL; - - close (); - - if (epih->pending) - epih->destroyed = true; - else - delete epih; - - delete tpc; - - delete ppframe; - delete leftbox; - delete vboxright; - //delete saveAsDialog; - if(catalogPane) - delete catalogPane; - - if (iTopPanel_1_Show) delete iTopPanel_1_Show; - if (iTopPanel_1_Hide) delete iTopPanel_1_Hide; - if (iHistoryShow) - delete iHistoryShow; - if (iHistoryHide) - delete iHistoryHide; - if(iBeforeLockON) - delete iBeforeLockON; - if(iBeforeLockOFF) - delete iBeforeLockOFF; - if(iRightPanel_1_Show) - delete iRightPanel_1_Show; - if(iRightPanel_1_Hide) - delete iRightPanel_1_Hide; -} - -void EditorPanel::leftPaneButtonReleased(GdkEventButton *event) { - if (event->button == 1) { - // Button 1 released : it's a resize - options.historyPanelWidth = hpanedl->get_position(); - } - /*else if (event->button == 3) { - }*/ -} - -void EditorPanel::rightPaneButtonReleased(GdkEventButton *event) { - if (event->button == 1) { - int winW, winH; - parent->get_size(winW, winH); - // Button 1 released : it's a resize - options.toolPanelWidth = winW - hpanedr->get_position(); - } - /*else if (event->button == 3) { - }*/ -} - -void EditorPanel::writeOptions() { - if (profilep) - profilep->writeOptions(); - if (tpc) - tpc->writeOptions(); -} - -void EditorPanel::showTopPanel(bool show) { - if (tbTopPanel_1->get_active() != show) - tbTopPanel_1->set_active(show); -} - -void EditorPanel::setAspect () { - int winW, winH; - parent->get_size(winW, winH); - hpanedl->set_position(options.historyPanelWidth); - hpanedr->set_position(winW - options.toolPanelWidth); - // initialize components - if (info->get_active() != options.showInfo) - info->set_active (options.showInfo); -} - -void EditorPanel::on_realize () { - realized = true; - Gtk::VBox::on_realize (); - // This line is needed to avoid autoexpansion of the window :-/ - vboxright->set_size_request (options.toolPanelWidth, -1); - tpc->updateToolState(); -} - -void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) { - - close(); - - isProcessing=true; // prevents closing-on-init - - // initialize everything - openThm = tmb; - openThm->increaseRef (); - - fname=openThm->getFileName(); - lastSaveAsFileName = removeExtension (Glib::path_get_basename (fname)); - - previewHandler = new PreviewHandler (); - previewHandler2 = new PreviewHandler (); - - this->isrc = isrc; - ipc = rtengine::StagedImageProcessor::create (isrc); - ipc->setProgressListener (this); - ipc->setPreviewImageListener (previewHandler); - ipc->setPreviewScale (10); // Important - tpc->initImage (ipc, tmb->getType()==FT_Raw); - ipc->setHistogramListener (this); - -// iarea->fitZoom (); // tell to the editorPanel that the next image has to be fitted to the screen - iareapanel->imageArea->setPreviewHandler (previewHandler); - iareapanel->imageArea->setImProcCoordinator (ipc); - navigator->previewWindow->setPreviewHandler (previewHandler); - navigator->previewWindow->setImageArea (iareapanel->imageArea); - - rtengine::ImageSource* is=isrc->getImageSource(); - is->setProgressListener( this ); - - // try to load the last saved parameters from the cache or from the paramfile file - ProcParams* ldprof = openThm->createProcParamsForUpdate(true,false); // will be freed by initProfile - - // initialize profile - Glib::ustring defProf = openThm->getType()==FT_Raw ? options.defProfRaw : options.defProfImg; - profilep->initProfile (defProf, ldprof); - profilep->setInitialFileName (fname); - - openThm->addThumbnailListener (this); - info_toggled (); - - if (beforeIarea) - { - beforeAfterToggled(); - beforeAfterToggled(); - } - - // If in single tab mode, the main crop window is not constructed the very first time - // since there was no resize event - if (iareapanel->imageArea->mainCropWindow) - { - iareapanel->imageArea->mainCropWindow->cropHandler.newImage(ipc, false); - iareapanel->imageArea->mainCropWindow->initialImageArrived(); - - // In single tab mode, the image is not always updated between switches - // normal redraw don't work, so this is the hard way - // Disabled this with Issue 2435 because it seems to work fine now -// if (!options.tabbedUI && iareapanel->imageArea->mainCropWindow->getZoomFitVal() == 1.0) { -// iareapanel->imageArea->mainCropWindow->cropHandler.update(); -// } - } else { - Gtk::Allocation alloc; - iareapanel->imageArea->on_resized(alloc); - } -} - -void EditorPanel::close () { - if (ipc) - { - saveProfile (); - // close image processor and the current thumbnail - tpc->closeImage (); // this call stops image processing - tpc->writeOptions (); - rtengine::ImageSource* is=isrc->getImageSource(); - is->setProgressListener( NULL ); - - if (ipc) { - ipc->setPreviewImageListener (NULL); - } - - if (beforeIpc){ - beforeIpc->setPreviewImageListener (NULL); - } - - delete previewHandler; - previewHandler= NULL; - - if(iareapanel) - { - iareapanel->imageArea->setPreviewHandler (NULL); - iareapanel->imageArea->setImProcCoordinator (NULL); - } - rtengine::StagedImageProcessor::destroy (ipc); - ipc = NULL; - navigator->previewWindow->setPreviewHandler (NULL); - - // If the file was deleted somewhere, the openThm.descreaseRef delete the object, but we don't know here - if (safe_file_test(fname, Glib::FILE_TEST_EXISTS)) { - openThm->removeThumbnailListener (this); - openThm->decreaseRef (); - } - } -} - -void EditorPanel::saveProfile () { - if (!ipc || !openThm) return; - - // If the file was deleted, do not generate ghost entries - if (safe_file_test(fname, Glib::FILE_TEST_EXISTS)) { - ProcParams params; - ipc->getParams (¶ms); - - // Will call updateCache, which will update both the cached and sidecar files if necessary - openThm->setProcParams (params, NULL, EDITOR); -} -} - -Glib::ustring EditorPanel::getShortName () { - if (openThm) return Glib::path_get_basename (openThm->getFileName ()); - else return ""; -} - -Glib::ustring EditorPanel::getFileName () { - if (openThm) return openThm->getFileName (); - else return ""; -} - -// TODO!!! -void EditorPanel::procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) { - -// if (ev!=EvPhotoLoaded) -// saveLabel->set_markup (Glib::ustring("") + M("MAIN_BUTTON_SAVE") + ""); -} - -struct spsparams { - bool inProcessing; - EditorPanelIdleHelper* epih; -}; - -int setProgressStateUIThread (void* data) { - - spsparams* p = static_cast(data); - - if (p->epih->destroyed) { - if (p->epih->pending == 1) - delete p->epih; - else - p->epih->pending--; - delete p; - - return 0; - } - - p->epih->epanel->refreshProcessingState (p->inProcessing); - p->epih->pending--; - delete p; - - return 0; -} - -void EditorPanel::setProgressState (bool inProcessing) { - - epih->pending++; - - spsparams* p = new spsparams; - p->inProcessing = inProcessing; - p->epih = epih; - g_idle_add (setProgressStateUIThread, p); -} - -struct spparams { - double val; - Glib::ustring str; - Gtk::ProgressBar *pProgress; -}; - -int setprogressStrUI( void *p ) -{ - GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected - spparams *s= static_cast(p); - - if( ! s->str.empty() ) - s->pProgress->set_text( M(s->str) ); - if( s->val >=0 ){ - s->pProgress->set_fraction( s->val ); - if( s->val <1.0 ) - s->pProgress->modify_bg( Gtk::STATE_NORMAL,Gdk::Color("red") ); - else - s->pProgress->modify_bg( Gtk::STATE_NORMAL,Gdk::Color("grey") ); - } - - delete s; - return 0; -} - -void EditorPanel::setProgress (double p) -{ - spparams *s=new spparams; - s->val = p; - s->pProgress = progressLabel; - g_idle_add (setprogressStrUI, s); -} - -void EditorPanel::setProgressStr (Glib::ustring str) -{ - spparams *s=new spparams; - s->str = str; - s->val = -1; - s->pProgress = progressLabel; - g_idle_add (setprogressStrUI, s); -} - -// This is only called from the ThreadUI, so within the gtk thread -void EditorPanel::refreshProcessingState (bool inProcessingP) { - spparams *s=new spparams; - s->pProgress = progressLabel; - - if (inProcessingP) { - if (processingStartedTime==0) processingStartedTime = ::time(NULL); - - s->str = "PROGRESSBAR_PROCESSING"; - s->val = 0.0; - } else { - // Set proc params of thumbnail. It saves it into the cache and updates the file browser. - if (ipc && openThm && tpc->getChangedState()) { - rtengine::procparams::ProcParams pparams; - ipc->getParams (&pparams); - openThm->setProcParams (pparams, NULL, EDITOR, false); - } - - // Ring a sound if it was a long event - if (processingStartedTime!=0) { - time_t curTime= ::time(NULL); - if (::difftime(curTime, processingStartedTime) > options.sndLngEditProcDoneSecs) - SoundManager::playSoundAsync(options.sndLngEditProcDone); - - processingStartedTime = 0; - } - - // Set progress bar "done" - s->str = "PROGRESSBAR_READY"; - s->val = 1.0; - -#ifdef WIN32 - // Maybe accessing "parent", which is a Gtk object, can justify to get the Gtk lock... - if (!firstProcessingDone && static_cast(parent)->getIsFullscreen()) { parent->fullscreen(); } -#endif - firstProcessingDone = true; -} - - isProcessing=inProcessingP; - - setprogressStrUI(s); -} - -struct errparams { - Glib::ustring descr; - Glib::ustring title; - EditorPanelIdleHelper* epih; -}; - -void EditorPanel::displayError (Glib::ustring title, Glib::ustring descr) { - GtkWidget* msgd = gtk_message_dialog_new_with_markup (NULL, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - "%s", - descr.data()); - gtk_window_set_title((GtkWindow*)msgd, title.data()); - g_signal_connect_swapped (msgd, "response", - G_CALLBACK (gtk_widget_destroy), - msgd); - gtk_widget_show_all (msgd); -} - -int disperrorUI (void* data) { - errparams* p = static_cast(data); - - if (p->epih->destroyed) { - if (p->epih->pending == 1) - delete p->epih; - else - p->epih->pending--; - delete p; - - return 0; - } - - p->epih->epanel->displayError (p->title, p->descr); - p->epih->pending--; - delete p; - - return 0; -} - -void EditorPanel::error (Glib::ustring title, Glib::ustring descr) { - - epih->pending++; - errparams* p = new errparams; - p->descr = descr; - p->title = title; - p->epih = epih; - g_idle_add (disperrorUI, p); -} - -void EditorPanel::info_toggled () { - - Glib::ustring infoString; - Glib::ustring infoString1; //1-st line - Glib::ustring infoString2; //2-nd line - Glib::ustring infoString3; //3-rd line - Glib::ustring infoString4; //4-th line - Glib::ustring expcomp; - - if (!ipc || !openThm) return; - const rtengine::ImageMetaData* idata = ipc->getInitialImage()->getMetaData(); - if (idata && idata->hasExif()){ - infoString1 = Glib::ustring::compose ("%1 + %2", - Glib::ustring(idata->getMake()+" "+idata->getModel()), - Glib::ustring(idata->getLens())); - - infoString2 = Glib::ustring::compose ("f/%1 %2s %3%4 %5mm", - Glib::ustring(idata->apertureToString(idata->getFNumber())), - Glib::ustring(idata->shutterToString(idata->getShutterSpeed())), - M("QINFO_ISO"), idata->getISOSpeed(), - Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), idata->getFocalLen())); - - expcomp = Glib::ustring(idata->expcompToString(idata->getExpComp(),true)); // maskZeroexpcomp - if (expcomp!=""){ - infoString2 = Glib::ustring::compose("%1 %2EV", - infoString2, - expcomp /*Glib::ustring(idata->expcompToString(idata->getExpComp()))*/); - } - - infoString3 = Glib::ustring::compose ("%1%2", - escapeHtmlChars(Glib::path_get_dirname(openThm->getFileName())) + G_DIR_SEPARATOR_S, - escapeHtmlChars(Glib::path_get_basename(openThm->getFileName())) ); - - int ww= ipc->getFullWidth(); - int hh= ipc->getFullHeight(); - //megapixels - infoString4 = Glib::ustring::compose ("%1 MP (%2x%3)", Glib::ustring::format(std::setw(4), std::fixed, std::setprecision(1), (float)ww*hh/1000000), ww, hh); - - infoString = Glib::ustring::compose ("%1\n%2\n%3\n%4",infoString1, infoString2, infoString3, infoString4); - } - else - infoString = M("QINFO_NOEXIF"); - - iareapanel->imageArea->setInfoText (infoString); - iareapanel->imageArea->infoEnabled (info->get_active ()); -} - -void EditorPanel::hideHistoryActivated () { - - removeIfThere (hpanedl, leftbox, false); - if (hidehp->get_active()) - hpanedl->pack1 (*leftbox, false, true); - options.showHistory = hidehp->get_active(); - - if (options.showHistory){ - hidehp->set_image (*iHistoryHide); - } - else { - hidehp->set_image (*iHistoryShow); - } - - tbShowHideSidePanels_managestate(); -} - - -void EditorPanel::tbRightPanel_1_toggled () { -/* - removeIfThere (hpanedr, vboxright, false); - if (tbRightPanel_1->get_active()){ - hpanedr->pack2(*vboxright, false, true); - tbRightPanel_1->set_image (*iRightPanel_1_Hide); - } - else { - tbRightPanel_1->set_image (*iRightPanel_1_Show); - } - tbShowHideSidePanels_managestate(); - */ - if (vboxright){ - if (tbRightPanel_1->get_active()){ - vboxright->show(); - tbRightPanel_1->set_image (*iRightPanel_1_Hide); - } - else{ - vboxright->hide(); - tbRightPanel_1->set_image (*iRightPanel_1_Show); - } - tbShowHideSidePanels_managestate(); - } -} - -void EditorPanel::tbTopPanel_1_visible (bool visible){ - if (!tbTopPanel_1) - return; - - if (visible) - tbTopPanel_1->show(); - else - tbTopPanel_1->hide(); -} - -void EditorPanel::tbTopPanel_1_toggled () { - - if (catalogPane){ // catalogPane does not exist in multitab mode - - if (tbTopPanel_1->get_active()){ - catalogPane->show(); - tbTopPanel_1->set_image (*iTopPanel_1_Hide); - options.editorFilmStripOpened = true; - } - else { - catalogPane->hide(); - tbTopPanel_1->set_image (*iTopPanel_1_Show); - options.editorFilmStripOpened = false; - } - - tbShowHideSidePanels_managestate(); - } -} - -/* - * WARNING: Take care of the simpleEditor value when adding or modifying shortcut keys, - * since handleShortcutKey is now also triggered in simple editor mode - */ -bool EditorPanel::handleShortcutKey (GdkEventKey* event) { - - bool ctrl = event->state & GDK_CONTROL_MASK; - bool shift = event->state & GDK_SHIFT_MASK; - bool alt = event->state & GDK_MOD1_MASK; -#ifdef __WIN32__ - bool altgr = event->state & GDK_MOD2_MASK; -#else - bool altgr = event->state & GDK_MOD5_MASK; -#endif - - // Editor Layout - switch(event->keyval) { - case GDK_L: - if (tbTopPanel_1) - tbTopPanel_1->set_active (!tbTopPanel_1->get_active()); // toggle top panel - if (ctrl) hidehp->set_active (!hidehp->get_active()); // toggle History (left panel) - if (alt) tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); // toggle right panel - return true; - break; - case GDK_l: - if (!shift && !alt /*&& !ctrl*/){ - hidehp->set_active (!hidehp->get_active()); // toggle History (left panel) - return true; - } - if (alt && !ctrl){ // toggle right panel - tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); - return true; - } - if (alt && ctrl){ // toggle left and right panels - hidehp->set_active (!hidehp->get_active()); - tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); - return true; - } - break; - case GDK_m: // Maximize preview panel: hide top AND right AND history panels - if (!ctrl && !alt) { - toggleSidePanels(); - return true; - } - break; - case GDK_M: // Maximize preview panel: hide top AND right AND history panels AND (fit image preview) - if (!ctrl && !alt) { - toggleSidePanelsZoomFit(); - return true; - } - break; - } -#ifdef __WIN32__ - if (!alt && !ctrl && !altgr && event->hardware_keycode == 0x39 ) { - iareapanel->imageArea->previewModePanel->togglebackColor(); - return true; - } -#else - if (!alt && !ctrl && !altgr && event->hardware_keycode == 0x12 ) { - iareapanel->imageArea->previewModePanel->togglebackColor(); - return true; - } -#endif - if (!alt){ - if (!ctrl) { - // Normal - switch(event->keyval) { - case GDK_bracketright: - tpc->coarse->rotateRight(); - return true; - case GDK_bracketleft: - tpc->coarse->rotateLeft(); - return true; - case GDK_i: - case GDK_I: - info->set_active (!info->get_active()); - return true; - case GDK_B: - beforeAfter->set_active (!beforeAfter->get_active()); - return true; - case GDK_plus: - case GDK_equal: - case GDK_KP_Add: - iareapanel->imageArea->zoomPanel->zoomInClicked(); - return true; - case GDK_minus: - case GDK_underscore: - case GDK_KP_Subtract: - iareapanel->imageArea->zoomPanel->zoomOutClicked(); - return true; - case GDK_z://GDK_1 - iareapanel->imageArea->zoomPanel->zoom11Clicked(); - return true; -/* -#ifndef __WIN32__ - case GDK_9: // toggle background color of the preview - iareapanel->imageArea->previewModePanel->togglebackColor(); - return true; -#endif -*/ - case GDK_r: //preview mode Red - iareapanel->imageArea->previewModePanel->toggleR(); - return true; - case GDK_g: //preview mode Green - iareapanel->imageArea->previewModePanel->toggleG(); - return true; - case GDK_b: //preview mode Blue - iareapanel->imageArea->previewModePanel->toggleB(); - return true; - case GDK_v: //preview mode Luminosity - iareapanel->imageArea->previewModePanel->toggleL(); - return true; - case GDK_F: //preview mode Focus Mask - iareapanel->imageArea->previewModePanel->toggleFocusMask(); - return true; - - case GDK_f: - iareapanel->imageArea->zoomPanel->zoomFitClicked(); - return true; - case GDK_less: - iareapanel->imageArea->indClippedPanel->toggleClipped(true); - return true; - case GDK_greater: - iareapanel->imageArea->indClippedPanel->toggleClipped(false); - return true; - - case GDK_F5: - openThm->openDefaultViewer((event->state & GDK_SHIFT_MASK) ? 2 : 1); - return true; - case GDK_y: // synchronize filebrowser with image in Editor - if (!simpleEditor && fPanel && !fname.empty()){ - fPanel->fileCatalog->selectImage(fname, false); - return true; - } - break; // to avoid gcc complain - case GDK_x: // clear filters and synchronize filebrowser with image in Editor - if (!simpleEditor && fPanel && !fname.empty()){ - fPanel->fileCatalog->selectImage(fname, true); - return true; - } - break; // to avoid gcc complain - } - } - else { - // With control - switch (event->keyval) { - case GDK_S: - saveProfile(); - setProgressStr(M("PROGRESSBAR_PROCESSING_PROFILESAVED")); - return true; - case GDK_s: - saveAsPressed(); - return true; - case GDK_b: - if (!simpleEditor) - queueImgPressed(); - return true; - case GDK_e: - sendToGimpPressed(); - return true; - case GDK_z: - history->undo (); - return true; - case GDK_Z: - history->redo (); - return true; - case GDK_F5: - openThm->openDefaultViewer(3); - return true; - } - } //if (!ctrl) - } //if (!alt) - - if (alt){ - switch (event->keyval) { - case GDK_s: - history->addBookmarkPressed (); - setProgressStr(M("PROGRESSBAR_SNAPSHOT_ADDED")); - return true; - case GDK_f: - iareapanel->imageArea->zoomPanel->zoomFitCropClicked(); - return true; - } - } - - if (shift){ - switch (event->keyval) { - case GDK_F3: // open Previous image from Editor's perspective - if (!simpleEditor && fPanel && !fname.empty()){ - EditorPanel::openPreviousEditorImage(); - return true; - } - break; // to avoid gcc complain - case GDK_F4: // open next image from Editor's perspective - if (!simpleEditor && fPanel && !fname.empty()){ - EditorPanel::openNextEditorImage(); - return true; - } - break; // to avoid gcc complain - } - } - - if(tpc->getToolBar() && tpc->getToolBar()->handleShortcutKey(event)) - return true; - if(tpc->handleShortcutKey(event)) - return true; - - if (!simpleEditor && fPanel){ - if (fPanel->handleShortcutKey(event)) - return true; - } - - return false; -} - -void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt) { - - if (whoChangedIt!=EDITOR) { - PartialProfile pp(true); - pp.set(true); - *(pp.pparams) = openThm->getProcParams(); - tpc->profileChange (&pp, rtengine::EvProfileChangeNotification, M("PROGRESSDLG_PROFILECHANGEDINBROWSER")); - pp.deleteInstance(); - } -} - -bool EditorPanel::idle_saveImage (ProgressConnector *pc, Glib::ustring fname, SaveFormat sf) { - rtengine::IImage16* img = pc->returnValue(); - delete pc; - if( img ) { - setProgressStr(M("GENERAL_SAVE")); setProgress(0.9f); - - ProgressConnector *ld = new ProgressConnector(); - img->setSaveProgressListener (parent->getProgressListener()); - if (sf.format=="tif") - ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsTIFF), fname, sf.tiffBits, sf.tiffUncompressed), - sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fname, sf)); - else if (sf.format=="png") - ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsPNG), fname, sf.pngCompression, sf.pngBits), - sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fname, sf)); - else if (sf.format=="jpg") - ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsJPEG), fname, sf.jpegQuality, sf.jpegSubSamp), - sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fname, sf)); - } else { - Glib::ustring msg_ = Glib::ustring("") + fname + ": Error during image processing\n"; - Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); - msgd.run (); - - saveimgas->set_sensitive(true); - sendtogimp->set_sensitive(true); - isProcessing = false; - - } - rtengine::ImageSource* imgsrc = isrc->getImageSource (); - imgsrc->setProgressListener(this); - return false; -} - -bool EditorPanel::idle_imageSaved(ProgressConnector *pc,rtengine::IImage16* img,Glib::ustring fname, SaveFormat sf){ - img->free (); - - if (! pc->returnValue() ) { - openThm->imageDeveloped (); - // save processing parameters, if needed - if (sf.saveParams) { - rtengine::procparams::ProcParams pparams; - ipc->getParams (&pparams); - // We keep the extension to avoid overwriting the profile when we have - // the same output filename with different extension - //pparams.save (removeExtension (fname) + ".out" + paramFileExtension); - pparams.save (fname + ".out" + paramFileExtension); - } - } else { - error(M("MAIN_MSG_CANNOTSAVE"), fname); - } - - saveimgas->set_sensitive(true); - sendtogimp->set_sensitive(true); - - parent->setProgressStr(""); - parent->setProgress(0.); - - setProgressState(false); - - delete pc; - SoundManager::playSoundAsync(options.sndBatchQueueDone); - isProcessing = false; - return false; -} - -BatchQueueEntry* EditorPanel::createBatchQueueEntry () { - - rtengine::procparams::ProcParams pparams; - ipc->getParams (&pparams); - //rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); - rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (openThm->getFileName (), openThm->getType()==FT_Raw, pparams); - int fullW=0, fullH=0; - isrc->getImageSource()->getFullSize(fullW, fullH, pparams.coarse.rotate==90 || pparams.coarse.rotate==270 ? TR_R90 : TR_NONE); - int prevh = BatchQueue::calcMaxThumbnailHeight(); - int prevw = int((size_t)fullW * (size_t)prevh / (size_t)fullH); - return new BatchQueueEntry (job, pparams, openThm->getFileName(), prevw, prevh, openThm); -} - - - -void EditorPanel::saveAsPressed () { - if (!ipc || !openThm) return; - bool fnameOK = false; - Glib::ustring fnameOut; - - SaveAsDialog* saveAsDialog; - if (safe_file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR)) - saveAsDialog = new SaveAsDialog (options.lastSaveAsPath); - else - saveAsDialog = new SaveAsDialog (safe_get_user_picture_dir()); - - saveAsDialog->set_default_size (options.saveAsDialogWidth, options.saveAsDialogHeight); - saveAsDialog->setInitialFileName (lastSaveAsFileName); - saveAsDialog->setImagePath (fname); - - do { - int result = saveAsDialog->run (); - - // The SaveAsDialog ensure that a filename has been specified - fnameOut = saveAsDialog->getFileName (); - - options.lastSaveAsPath = saveAsDialog->getDirectory (); - options.saveAsDialogWidth = saveAsDialog->get_width (); - options.saveAsDialogHeight = saveAsDialog->get_height (); - options.autoSuffix = saveAsDialog->getAutoSuffix (); - options.saveMethodNum = saveAsDialog->getSaveMethodNum (); - lastSaveAsFileName = Glib::path_get_basename (removeExtension (fnameOut)); - SaveFormat sf = saveAsDialog->getFormat (); - options.saveFormat = sf; - options.forceFormatOpts = saveAsDialog->getForceFormatOpts (); - - if (result != Gtk::RESPONSE_OK) - break; - - if (saveAsDialog->getImmediately ()) { - // separate filename and the path to the destination directory - Glib::ustring dstdir = Glib::path_get_dirname (fnameOut); - Glib::ustring dstfname = Glib::path_get_basename (removeExtension(fnameOut)); - Glib::ustring dstext = getExtension (fnameOut); - - if (saveAsDialog->getAutoSuffix()) { - - Glib::ustring fnameTemp; - for (int tries=0; tries<100; tries++) { - if (tries==0) - fnameTemp = Glib::ustring::compose ("%1.%2", Glib::build_filename (dstdir, dstfname), dstext); - else - fnameTemp = Glib::ustring::compose ("%1-%2.%3", Glib::build_filename (dstdir, dstfname), tries, dstext); - - if (!safe_file_test (fnameTemp, Glib::FILE_TEST_EXISTS)) { - fnameOut = fnameTemp; - fnameOK = true; - break; - } - } - } - // check if it exists - if (!fnameOK) { - fnameOK = confirmOverwrite (*saveAsDialog, fnameOut); - } - - if (fnameOK) { - isProcessing = true; - // save image - rtengine::procparams::ProcParams pparams; - ipc->getParams (&pparams); - rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); - - ProgressConnector *ld = new ProgressConnector(); - ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener(), options.tunnelMetaData, false ), - sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_saveImage ),ld,fnameOut,sf )); - saveimgas->set_sensitive(false); - sendtogimp->set_sensitive(false); - } - } - else { - BatchQueueEntry* bqe = createBatchQueueEntry (); - bqe->outFileName = fnameOut; - bqe->saveFormat = saveAsDialog->getFormat (); - bqe->forceFormatOpts = saveAsDialog->getForceFormatOpts (); - parent->addBatchQueueJob (bqe, saveAsDialog->getToHeadOfQueue ()); - fnameOK = true; - } - // ask parent to redraw file browser - // ... or does it automatically when the tab is switched to it - } while (!fnameOK); - - saveAsDialog->hide(); -} - -void EditorPanel::queueImgPressed () { - if (!ipc || !openThm) return; - saveProfile (); - parent->addBatchQueueJob (createBatchQueueEntry ()); -} - -void EditorPanel::sendToGimpPressed () { - if (!ipc || !openThm) return; - // develop image - rtengine::procparams::ProcParams pparams; - ipc->getParams (&pparams); - rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); - ProgressConnector *ld = new ProgressConnector(); - ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener(), options.tunnelMetaData, false ), - sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_sendToGimp ),ld, openThm->getFileName() )); - saveimgas->set_sensitive(false); - sendtogimp->set_sensitive(false); -} - - -void EditorPanel::openPreviousEditorImage() { - if (!simpleEditor && fPanel && !fname.empty()) - fPanel->fileCatalog->openNextPreviousEditorImage(fname, false, NAV_PREVIOUS); -} - -void EditorPanel::openNextEditorImage() { - if (!simpleEditor && fPanel && !fname.empty()) - fPanel->fileCatalog->openNextPreviousEditorImage(fname, false, NAV_NEXT); -} - -void EditorPanel::syncFileBrowser() { // synchronize filebrowser with image in Editor - if (!simpleEditor && fPanel && !fname.empty()) - fPanel->fileCatalog->selectImage(fname, false); -} - -bool EditorPanel::idle_sendToGimp( ProgressConnector *pc, Glib::ustring fname){ - - rtengine::IImage16* img = pc->returnValue(); - delete pc; - if (img) { - // get file name base - Glib::ustring shortname = removeExtension (Glib::path_get_basename (fname)); - Glib::ustring dirname = Glib::get_tmp_dir (); - Glib::ustring fname = Glib::build_filename (dirname, shortname); - - SaveFormat sf; - sf.format = "tif"; - sf.tiffBits = 16; - sf.tiffUncompressed = true; - sf.saveParams = true; - - Glib::ustring fileName = Glib::ustring::compose ("%1.%2", fname, sf.format); - - int tries = 1; - while (safe_file_test (fileName, Glib::FILE_TEST_EXISTS) && tries<1000) { - fileName = Glib::ustring::compose("%1-%2.%3", fname, tries, sf.format); - tries++; - } - if (tries==1000){ - img->free (); - return false; - } - - ProgressConnector *ld = new ProgressConnector(); - img->setSaveProgressListener (parent->getProgressListener()); - ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsTIFF), fileName, sf.tiffBits, sf.tiffUncompressed), - sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_sentToGimp), ld, img, fileName)); - }else{ - Glib::ustring msg_ = Glib::ustring(" Error during image processing\n"); - Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); - msgd.run (); - saveimgas->set_sensitive(true); - sendtogimp->set_sensitive(true); - } - return false; -} - -bool EditorPanel::idle_sentToGimp(ProgressConnector *pc,rtengine::IImage16* img,Glib::ustring filename){ - img->free (); - int errore = pc->returnValue(); - delete pc; - if (!errore) { - saveimgas->set_sensitive(true); - sendtogimp->set_sensitive(true); - parent->setProgressStr(""); - parent->setProgress(0.); - bool success=false; - Glib::ustring cmdLine; - Glib::ustring executable; - // start gimp - if (options.editorToSendTo==1) { -#ifdef WIN32 - executable = Glib::build_filename (Glib::build_filename(options.gimpDir,"bin"), "gimp-win-remote"); - cmdLine = Glib::ustring("\"") + executable + Glib::ustring("\" gimp-2.4.exe ") + Glib::ustring("\"") + filename + Glib::ustring("\""); - if ( safe_file_test(executable, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) { - success = safe_spawn_command_line_async (cmdLine); - } -#elif defined __APPLE__ - cmdLine = Glib::ustring("open -a /Applications/GIMP.app \'") + filename + Glib::ustring("\'"); - success = safe_spawn_command_line_async (cmdLine); - std::cout << cmdLine << std::endl; -#else - cmdLine = Glib::ustring("gimp \"") + filename + Glib::ustring("\""); - success = safe_spawn_command_line_async (cmdLine); - std::cout << cmdLine << std::endl; -#endif - if (!success){ -#ifdef WIN32 - int ver = 12; - while (!success && ver) { - executable = Glib::build_filename (Glib::build_filename(options.gimpDir,"bin"), Glib::ustring::compose(Glib::ustring("gimp-2.%1.exe"),ver)); - if ( safe_file_test(executable, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) { - cmdLine = Glib::ustring("\"") + executable + Glib::ustring("\" \"") + filename + Glib::ustring("\""); - success = safe_spawn_command_line_async (cmdLine); - } - ver--; - } -#elif defined __APPLE__ - cmdLine = Glib::ustring("open -a /Applications/Gimp.app/Contents/Resources/start \'") + filename + Glib::ustring("\'"); - success = safe_spawn_command_line_async (cmdLine); - std::cout << cmdLine << std::endl; -#else - cmdLine = Glib::ustring("gimp-remote \"") + filename + Glib::ustring("\""); - success = safe_spawn_command_line_async (cmdLine); - std::cout << cmdLine << std::endl; -#endif - } - } - else if (options.editorToSendTo==2) { -#ifdef WIN32 - executable = Glib::build_filename(options.psDir,"Photoshop.exe"); - if ( safe_file_test(executable, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) { - cmdLine = Glib::ustring("\"") + executable + Glib::ustring("\" \"") + filename + Glib::ustring("\""); - success = safe_spawn_command_line_async (cmdLine); - } -#else - #ifdef __APPLE__ - cmdLine = Glib::ustring("open -a \'") + Glib::build_filename(options.psDir,"Photoshop.app\' ") + Glib::ustring("\'") + filename + Glib::ustring("\'"); - #else - cmdLine = Glib::ustring("\"") + Glib::build_filename(options.psDir,"Photoshop.exe") + Glib::ustring("\" \"") + filename + Glib::ustring("\""); - #endif - success = safe_spawn_command_line_async (cmdLine); - std::cout << cmdLine << std::endl; -#endif - } - else if (options.editorToSendTo==3) { -#ifdef WIN32 - if ( safe_file_test(options.customEditorProg, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) { - cmdLine = Glib::ustring("\"") + options.customEditorProg + Glib::ustring("\" \"") + filename + Glib::ustring("\""); - success = safe_spawn_command_line_async (cmdLine); - } -#else - #ifdef __APPLE__ - cmdLine = options.customEditorProg + Glib::ustring(" \"") + filename + Glib::ustring("\""); - #else - cmdLine = Glib::ustring("\"") + options.customEditorProg + Glib::ustring("\" \"") + filename + Glib::ustring("\""); - #endif - success = safe_spawn_command_line_async (cmdLine); - std::cout << cmdLine << std::endl; -#endif - } - - if (!success) { - Gtk::MessageDialog* msgd = new Gtk::MessageDialog (*parent, M("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); - msgd->set_secondary_text (M("MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY")); - msgd->set_title (M("MAIN_BUTTON_SENDTOEDITOR")); - msgd->run (); - delete msgd; - } - - } - - return false; -} - -void EditorPanel::historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) { - - if (beforeIpc) { - ProcParams* pparams = beforeIpc->beginUpdateParams (); - *pparams = params; - beforeIpc->endUpdateParams (rtengine::EvProfileChanged); // starts the IPC processing - } -} - -void EditorPanel::beforeAfterToggled () { - - if(!ipc) - return; - - removeIfThere (beforeAfterBox, beforeBox, false); - removeIfThere (afterBox, afterHeaderBox, false); - if (beforeIarea) { - if (beforeIpc) - beforeIpc->stopProcessing (); - iareapanel->setBeforeAfterViews (NULL, iareapanel); - iareapanel->imageArea->iLinkedImageArea = NULL; - delete beforeIarea; - beforeIarea = NULL; - if (beforeIpc) - { beforeIpc->setPreviewImageListener (NULL); - } - delete beforePreviewHandler; - beforePreviewHandler = NULL; - if (beforeIpc) - rtengine::StagedImageProcessor::destroy (beforeIpc); - beforeIpc = NULL; - } - - if (beforeAfter->get_active ()) { - - int errorCode=0; - rtengine::InitialImage *beforeImg = rtengine::InitialImage::load ( isrc->getImageSource ()->getFileName(), openThm->getType()==FT_Raw , &errorCode, NULL); - if( !beforeImg || errorCode ) - return; - - beforeIarea = new ImageAreaPanel (); - - int HeaderBoxHeight = 17; - - beforeLabel = Gtk::manage (new Gtk::Label ()); - beforeLabel->set_markup (Glib::ustring("") + M("GENERAL_BEFORE") + ""); - tbBeforeLock = Gtk::manage (new Gtk::ToggleButton ()); - tbBeforeLock->set_tooltip_markup (M("MAIN_TOOLTIP_BEFOREAFTERLOCK")); - tbBeforeLock->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::tbBeforeLock_toggled) ); - beforeHeaderBox = Gtk::manage (new Gtk::HBox ()); - beforeHeaderBox->pack_end (*tbBeforeLock, Gtk::PACK_SHRINK, 2); - beforeHeaderBox->pack_end (*beforeLabel, Gtk::PACK_SHRINK, 2); - beforeHeaderBox->set_size_request(0, HeaderBoxHeight); - - history->blistenerLock ? tbBeforeLock->set_image (*iBeforeLockON):tbBeforeLock->set_image (*iBeforeLockOFF); - tbBeforeLock->set_active(history->blistenerLock); - - beforeBox = Gtk::manage (new Gtk::VBox ()); - beforeBox->pack_start (*beforeHeaderBox, Gtk::PACK_SHRINK, 2); - beforeBox->pack_start (*beforeIarea); - - afterLabel = Gtk::manage (new Gtk::Label ()); - afterLabel->set_markup (Glib::ustring("") + M("GENERAL_AFTER") + ""); - afterHeaderBox = Gtk::manage (new Gtk::HBox ()); - afterHeaderBox->set_size_request(0, HeaderBoxHeight); - afterHeaderBox->pack_end (*afterLabel, Gtk::PACK_SHRINK, 2); - afterBox->pack_start (*afterHeaderBox, Gtk::PACK_SHRINK, 2); - afterBox->reorder_child (*afterHeaderBox, 0); - - beforeAfterBox->pack_start (*beforeBox); - beforeAfterBox->reorder_child (*beforeBox, 0); - beforeAfterBox->show_all (); - - beforePreviewHandler = new PreviewHandler (); - - beforeIpc = rtengine::StagedImageProcessor::create (beforeImg); - beforeIpc->setPreviewScale (10); - beforeIpc->setPreviewImageListener (beforePreviewHandler); - beforeIarea->imageArea->setPreviewHandler (beforePreviewHandler); - beforeIarea->imageArea->setImProcCoordinator (beforeIpc); - - beforeIarea->imageArea->setPreviewModePanel(iareapanel->imageArea->previewModePanel); - beforeIarea->imageArea->setIndicateClippedPanel(iareapanel->imageArea->indClippedPanel); - iareapanel->imageArea->iLinkedImageArea = beforeIarea->imageArea; - - iareapanel->setBeforeAfterViews (beforeIarea, iareapanel); - beforeIarea->setBeforeAfterViews (beforeIarea, iareapanel); - - rtengine::procparams::ProcParams params; - if (history->getBeforeLineParams (params)) - historyBeforeLineChanged (params); - } -} - -void EditorPanel::tbBeforeLock_toggled () { - history->blistenerLock = tbBeforeLock->get_active(); - tbBeforeLock->get_active()? tbBeforeLock->set_image (*iBeforeLockON) : tbBeforeLock->set_image (*iBeforeLockOFF); -} - -void EditorPanel::histogramChanged (LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve, /*LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, - LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw , LUTu & histChroma) { - - if (histogramPanel) histogramPanel->histogramChanged (histRed, histGreen, histBlue, histLuma, histRedRaw, histGreenRaw, histBlueRaw, histChroma); - tpc->updateCurveBackgroundHistogram (histToneCurve, histLCurve, histCCurve,/*histCLurve, histLLCurve,*/ histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma); -} - -bool EditorPanel::CheckSidePanelsVisibility() { - if (tbTopPanel_1) { - if(tbTopPanel_1->get_active()==false && tbRightPanel_1->get_active()==false && hidehp->get_active()==false) - return false; - return true; - } - if(tbRightPanel_1->get_active()==false && hidehp->get_active()==false) - return false; - return true; -} -void EditorPanel::toggleSidePanels(){ - // Maximize preview panel: - // toggle top AND right AND history panels - - bool bAllSidePanelsVisible; - bAllSidePanelsVisible= CheckSidePanelsVisibility(); - - if (tbTopPanel_1) - tbTopPanel_1->set_active (!bAllSidePanelsVisible); - tbRightPanel_1->set_active (!bAllSidePanelsVisible); - hidehp->set_active (!bAllSidePanelsVisible); - if (bAllSidePanelsVisible == false) - tbShowHideSidePanels->set_image (*iShowHideSidePanels); - else - tbShowHideSidePanels->set_image (*iShowHideSidePanels_exit); -} - -void EditorPanel::toggleSidePanelsZoomFit() { - toggleSidePanels(); - - // fit image preview - // !!! TODO this does not want to work... seems to have an effect on a subsequent key press - // iarea->imageArea->zoomPanel->zoomFitClicked(); -} - -void EditorPanel::tbShowHideSidePanels_managestate() { - bool bAllSidePanelsVisible; - bAllSidePanelsVisible = CheckSidePanelsVisibility(); - ShowHideSidePanelsconn.block (true); - - tbShowHideSidePanels->set_active (!bAllSidePanelsVisible); - - ShowHideSidePanelsconn.block (false); -} - -void EditorPanel::updateTPVScrollbar (bool hide) { - tpc->updateTPVScrollbar (hide); -} - -void EditorPanel::updateTabsUsesIcons (bool useIcons) { - tpc->updateTabsUsesIcons (useIcons); -} - -void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition) { - - switch (newPosition) { - case 0: - // No histogram - if (!oldPosition) { - // An histogram actually exist, we delete it - if (oldPosition == 1) - removeIfThere(leftbox, histogramPanel, false); - else if (oldPosition == 2) - removeIfThere(vboxright, histogramPanel, false); - delete histogramPanel; - histogramPanel = NULL; - } - // else no need to create it - break; - case 1: - // Histogram on the left pane - if (oldPosition == 0) { - // There was no Histogram before, so we create it - histogramPanel = Gtk::manage (new HistogramPanel ()); - leftbox->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2); - } - else if (oldPosition == 2) { - // The histogram was on the right side, so we move it to the left - histogramPanel->reference(); - removeIfThere(vboxright, histogramPanel, false); - leftbox->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2); - histogramPanel->unreference(); - } - histogramPanel->reorder(Gtk::ALIGN_LEFT); - leftbox->reorder_child(*histogramPanel, 0); - break; - case 2: - default: - // Histogram on the right pane - if (oldPosition == 0) { - // There was no Histogram before, so we create it - histogramPanel = Gtk::manage (new HistogramPanel ()); - vboxright->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2); - } - else if (oldPosition == 1) { - // The histogram was on the left side, so we move it to the right - histogramPanel->reference(); - removeIfThere(leftbox, histogramPanel, false); - vboxright->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2); - histogramPanel->unreference(); - } - histogramPanel->reorder(Gtk::ALIGN_RIGHT); - vboxright->reorder_child(*histogramPanel, 0); - break; - } - - iareapanel->imageArea->setPointerMotionHListener (histogramPanel); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2010 Oliver Duis + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "editorpanel.h" +#include "options.h" +#include "progressconnector.h" +#include "rtwindow.h" +#include "guiutils.h" +#include "procparamchangers.h" +#include "../rtengine/safegtk.h" +#include "../rtengine/imagesource.h" +#include "soundman.h" +#include "rtimage.h" +#include + +using namespace rtengine::procparams; + +EditorPanel::EditorPanel (FilePanel* filePanel) + : realized(false), iHistoryShow(NULL), iHistoryHide(NULL), iTopPanel_1_Show(NULL), iTopPanel_1_Hide(NULL), iRightPanel_1_Show(NULL), iRightPanel_1_Hide(NULL), iBeforeLockON(NULL),iBeforeLockOFF(NULL), beforePreviewHandler(NULL), beforeIarea(NULL), beforeBox(NULL), afterBox(NULL), afterHeaderBox(NULL), parent(NULL), openThm(NULL), ipc(NULL), beforeIpc(NULL), isProcessing(false), catalogPane(NULL) { + + epih = new EditorPanelIdleHelper; + epih->epanel = this; + epih->destroyed = false; + epih->pending = 0; + //rtengine::befaf=true; + processingStartedTime = 0; + firstProcessingDone = false; + + // construct toolpanelcoordinator + tpc = new ToolPanelCoordinator (); + + // build GUI + + // build left side panel + leftbox = new Gtk::VBox (); + leftbox->set_border_width (2); + leftbox->set_size_request(100,250); + + histogramPanel = NULL; + + profilep = Gtk::manage (new ProfilePanel ()); + ppframe = new Gtk::Frame (); + ppframe->add (*profilep); + ppframe->set_label (M("PROFILEPANEL_LABEL")); + //leftbox->pack_start (*ppframe, Gtk::PACK_SHRINK, 4); + + navigator = Gtk::manage (new Navigator ()); + navigator->previewWindow->set_size_request (-1, 150); + leftbox->pack_start (*navigator, Gtk::PACK_SHRINK, 2); + + history = Gtk::manage (new History ()); + leftbox->pack_start (*history); + + leftbox->show_all (); + + // build the middle of the screen + Gtk::VBox* editbox = Gtk::manage (new Gtk::VBox ()); + + info = Gtk::manage (new Gtk::ToggleButton ()); + Gtk::Image* infoimg = Gtk::manage (new RTImage ("info.png")); + info->add (*infoimg); + info->set_relief(Gtk::RELIEF_NONE); + info->set_tooltip_markup (M("MAIN_TOOLTIP_QINFO")); + + beforeAfter = Gtk::manage (new Gtk::ToggleButton ()); + Gtk::Image* beforeAfterIcon = Gtk::manage (new RTImage ("beforeafter.png")); + beforeAfter->add(*beforeAfterIcon); + beforeAfter->set_relief(Gtk::RELIEF_NONE); + beforeAfter->set_tooltip_markup (M("MAIN_TOOLTIP_TOGGLE")); + + iBeforeLockON = new RTImage ("lock-on.png"); + iBeforeLockOFF = new RTImage ("lock-off.png"); + + Gtk::VSeparator* vsept = Gtk::manage (new Gtk::VSeparator ()); + Gtk::VSeparator* vsepz = Gtk::manage (new Gtk::VSeparator ()); + Gtk::VSeparator* vsepi = Gtk::manage (new Gtk::VSeparator ()); + Gtk::VSeparator* vseph = Gtk::manage (new Gtk::VSeparator ()); + + hidehp = Gtk::manage (new Gtk::ToggleButton ()); + + iHistoryShow = new RTImage ("panel-to-right.png"); + iHistoryHide = new RTImage ("panel-to-left.png"); + + hidehp->set_relief(Gtk::RELIEF_NONE); + hidehp->set_active (options.showHistory); + hidehp->set_tooltip_markup (M("MAIN_TOOLTIP_HIDEHP")); + if (options.showHistory){ + hidehp->set_image (*iHistoryHide); + } + else { + hidehp->set_image (*iHistoryShow); + } + + tbTopPanel_1 = NULL; + if (!simpleEditor && filePanel) { + tbTopPanel_1 = new Gtk::ToggleButton (); + iTopPanel_1_Show = new RTImage ("panel-to-bottom.png"); + iTopPanel_1_Hide = new RTImage ("panel-to-top.png"); + tbTopPanel_1->set_relief(Gtk::RELIEF_NONE); + tbTopPanel_1->set_active (true); + tbTopPanel_1->set_tooltip_markup (M("MAIN_TOOLTIP_SHOWHIDETP1")); + tbTopPanel_1->set_image (*iTopPanel_1_Hide); + } + + tbRightPanel_1 = new Gtk::ToggleButton (); + iRightPanel_1_Show = new RTImage ("panel-to-left.png"); + iRightPanel_1_Hide = new RTImage ("panel-to-right.png"); + tbRightPanel_1->set_relief(Gtk::RELIEF_NONE); + tbRightPanel_1->set_active (true); + tbRightPanel_1->set_tooltip_markup (M("MAIN_TOOLTIP_SHOWHIDERP1")); + tbRightPanel_1->set_image (*iRightPanel_1_Hide); + + Gtk::VSeparator* vsepcl = Gtk::manage (new Gtk::VSeparator ()); + Gtk::VSeparator* vsepz2 = Gtk::manage (new Gtk::VSeparator ()); + Gtk::VSeparator* vsepz3 = Gtk::manage (new Gtk::VSeparator ()); + Gtk::VSeparator* vsepz4 = Gtk::manage (new Gtk::VSeparator ()); + + iareapanel = new ImageAreaPanel (); + tpc->setEditProvider(iareapanel->imageArea); + + Gtk::HBox* toolBarPanel = Gtk::manage (new Gtk::HBox ()); + toolBarPanel->pack_start (*hidehp, Gtk::PACK_SHRINK, 1); + toolBarPanel->pack_start (*vseph, Gtk::PACK_SHRINK, 2); + toolBarPanel->pack_start (*info, Gtk::PACK_SHRINK, 1); + toolBarPanel->pack_start (*beforeAfter, Gtk::PACK_SHRINK, 1); + toolBarPanel->pack_start (*vsepi, Gtk::PACK_SHRINK, 2); + toolBarPanel->pack_start (*tpc->getToolBar(), Gtk::PACK_SHRINK, 1); + toolBarPanel->pack_start (*vsept, Gtk::PACK_SHRINK, 2); + + if (tbTopPanel_1) { + toolBarPanel->pack_end (*tbTopPanel_1, Gtk::PACK_SHRINK, 1); + Gtk::VSeparator* vsep1 = Gtk::manage (new Gtk::VSeparator ()); + toolBarPanel->pack_end (*vsep1, Gtk::PACK_SHRINK, 2); + } + toolBarPanel->pack_end (*tpc->coarse, Gtk::PACK_SHRINK, 2); + toolBarPanel->pack_end (*vsepcl, Gtk::PACK_SHRINK, 2); + toolBarPanel->pack_end (*iareapanel->imageArea->indClippedPanel, Gtk::PACK_SHRINK, 0); + toolBarPanel->pack_end (*vsepz, Gtk::PACK_SHRINK, 2); + toolBarPanel->pack_end (*iareapanel->imageArea->previewModePanel, Gtk::PACK_SHRINK, 0); + toolBarPanel->pack_end (*vsepz4, Gtk::PACK_SHRINK, 2); + + afterBox = Gtk::manage (new Gtk::VBox ()); + afterBox->pack_start (*iareapanel); + + beforeAfterBox = Gtk::manage (new Gtk::HBox()); + beforeAfterBox->pack_start (*afterBox); + + editbox->pack_start (*toolBarPanel, Gtk::PACK_SHRINK,0); + editbox->pack_start (*beforeAfterBox); + + // build right side panel + vboxright = new Gtk::VBox (false, 0); + vboxright->set_size_request(100,250); + + vboxright->set_border_width (2); + + vboxright->pack_start (*ppframe, Gtk::PACK_SHRINK, 2); + // main notebook + vboxright->pack_start (*tpc->toolPanelNotebook); + + // Save buttons + Gtk::HBox* iops = Gtk::manage (new Gtk::HBox ()); + + //Gtk::Image *saveButtonImage = Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)); + Gtk::Image *saveButtonImage = Gtk::manage (new RTImage ("gtk-save-large.png")); + saveimgas = Gtk::manage (new Gtk::Button ()); + saveimgas->add(*saveButtonImage); + saveimgas->set_tooltip_markup(M("MAIN_BUTTON_SAVE_TOOLTIP")); + + Gtk::Image *queueButtonImage = Gtk::manage (new RTImage ("processing.png")); + queueimg = Gtk::manage (new Gtk::Button ()); + queueimg->add(*queueButtonImage); + queueimg->set_tooltip_markup(M("MAIN_BUTTON_PUTTOQUEUE_TOOLTIP")); + + Gtk::Image *sendToEditorButtonImage = Gtk::manage (new RTImage ("image-editor.png")); + sendtogimp = Gtk::manage (new Gtk::Button ()); + sendtogimp->add(*sendToEditorButtonImage); + sendtogimp->set_tooltip_markup(M("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP")); + + iops->pack_start (*saveimgas, Gtk::PACK_SHRINK); + if(!simpleEditor) + iops->pack_start (*queueimg, Gtk::PACK_SHRINK); + iops->pack_start (*sendtogimp, Gtk::PACK_SHRINK); + + // Status box + statusBox = Gtk::manage (new Gtk::HBox ()); + progressLabel = Gtk::manage (new Gtk::ProgressBar()); + progressLabel->set_fraction(0.0); + //progressLabel->modify_bg( Gtk::STATE_NORMAL,Gdk::Color("grey") ); // Disable, because in single mode this is may be permanent red without processing + + statusBox->pack_start (*progressLabel); + iops->pack_start(*statusBox, Gtk::PACK_SHRINK, 2); + + // tbRightPanel_1 + iops->pack_end (*tbRightPanel_1, Gtk::PACK_SHRINK,0); + + // ShowHideSidePanels + tbShowHideSidePanels = new Gtk::ToggleButton (); + iShowHideSidePanels = new RTImage ("crossed-arrows-out.png"); + iShowHideSidePanels_exit = new RTImage ("crossed-arrows-in.png"); + tbShowHideSidePanels->set_relief(Gtk::RELIEF_NONE); + tbShowHideSidePanels->set_active (false); + tbShowHideSidePanels->set_tooltip_markup (M("MAIN_BUTTON_SHOWHIDESIDEPANELS_TOOLTIP")); + tbShowHideSidePanels->set_image (*iShowHideSidePanels); + iops->pack_end (*tbShowHideSidePanels, Gtk::PACK_SHRINK,0); + iops->pack_end (*vsepz2, Gtk::PACK_SHRINK,1); + + // Zoom panel + iops->pack_end (*iareapanel->imageArea->zoomPanel, Gtk::PACK_SHRINK, 1); + iops->pack_end (*vsepz3, Gtk::PACK_SHRINK, 2); + + navPrev = navNext = navSync = NULL; + if (!simpleEditor && !options.tabbedUI){ + // Navigation buttons + Gtk::Image *navPrevImage = Gtk::manage (new RTImage ("nav-prev.png")); + navPrevImage->set_padding(0,0); + navPrev = Gtk::manage (new Gtk::Button ()); + navPrev->add(*navPrevImage); + navPrev->set_relief(Gtk::RELIEF_NONE); + navPrev->set_tooltip_markup(M("MAIN_BUTTON_NAVPREV_TOOLTIP")); + + Gtk::Image *navNextImage = Gtk::manage (new RTImage ("nav-next.png")); + navNextImage->set_padding(0,0); + navNext = Gtk::manage (new Gtk::Button ()); + navNext->add(*navNextImage); + navNext->set_relief(Gtk::RELIEF_NONE); + navNext->set_tooltip_markup(M("MAIN_BUTTON_NAVNEXT_TOOLTIP")); + + Gtk::Image *navSyncImage = Gtk::manage (new RTImage ("nav-sync.png")); + navSyncImage->set_padding(0,0); + navSync = Gtk::manage (new Gtk::Button ()); + navSync->add(*navSyncImage); + navSync->set_relief(Gtk::RELIEF_NONE); + navSync->set_tooltip_markup(M("MAIN_BUTTON_NAVSYNC_TOOLTIP")); + + iops->pack_end (*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_SHRINK, 0); + iops->pack_end (*navNext, Gtk::PACK_SHRINK, 0); + iops->pack_end (*navSync, Gtk::PACK_SHRINK, 0); + iops->pack_end (*navPrev, Gtk::PACK_SHRINK, 0); + } + + editbox->pack_start (*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0); + editbox->pack_start (*iops, Gtk::PACK_SHRINK, 0); + editbox->show_all (); + + // build screen + hpanedl = Gtk::manage (new Gtk::HPaned()); + hpanedr = Gtk::manage (new Gtk::HPaned()); + leftbox->reference (); + vboxright->reference (); + if (options.showHistory) { + hpanedl->pack1(*leftbox, false, true); + hpanedl->set_position (options.historyPanelWidth); + } + + + Gtk::VPaned * viewpaned = Gtk::manage (new Gtk::VPaned()); + fPanel = filePanel; + if(filePanel) + { + catalogPane = new Gtk::Paned(); + viewpaned->pack1(*catalogPane, false, true); + } + viewpaned->pack2(*editbox, true, true); + + + Gtk::Frame* vbfr = Gtk::manage (new Gtk::Frame ()); + vbfr->add (*viewpaned); + vbfr->set_size_request(100,250); + hpanedl->pack2(*vbfr, true, true); + + hpanedr->pack1(*hpanedl, true, true); + hpanedr->pack2(*vboxright, false, true); + hpanedl->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &EditorPanel::leftPaneButtonReleased) ); + hpanedr->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &EditorPanel::rightPaneButtonReleased) ); + + pack_start (*hpanedr); + + updateHistogramPosition (0, options.histogramPosition); + + show_all (); +/* + // save as dialog + if (safe_file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR)) + saveAsDialog = new SaveAsDialog (options.lastSaveAsPath); + else + saveAsDialog = new SaveAsDialog (safe_get_user_picture_dir()); + + saveAsDialog->set_default_size (options.saveAsDialogWidth, options.saveAsDialogHeight); +*/ + // connect listeners + profilep->setProfileChangeListener (tpc); + history->setProfileChangeListener (tpc); + history->setHistoryBeforeLineListener (this); + tpc->addPParamsChangeListener (profilep); + tpc->addPParamsChangeListener (history); + tpc->addPParamsChangeListener (this); + iareapanel->imageArea->setCropGUIListener (tpc->getCropGUIListener()); + iareapanel->imageArea->setPointerMotionListener (navigator); + iareapanel->imageArea->setImageAreaToolListener (tpc); + + // initialize components + info->set_active (options.showInfo); + tpc->readOptions (); + + // connect event handlers + info->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::info_toggled) ); + beforeAfter->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::beforeAfterToggled) ); + hidehp->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::hideHistoryActivated) ); + tbRightPanel_1->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::tbRightPanel_1_toggled) ); + saveimgas->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::saveAsPressed) ); + queueimg->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::queueImgPressed) ); + sendtogimp->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::sendToGimpPressed) ); + if(navPrev) + navPrev->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::openPreviousEditorImage) ); + if(navNext) + navNext->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::openNextEditorImage) ); + if(navSync) + navSync->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::syncFileBrowser) ); + ShowHideSidePanelsconn = tbShowHideSidePanels->signal_toggled().connect ( sigc::mem_fun(*this, &EditorPanel::toggleSidePanels), true); + if (tbTopPanel_1) + tbTopPanel_1->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::tbTopPanel_1_toggled) ); +} + +EditorPanel::~EditorPanel () { + + history->setHistoryBeforeLineListener (NULL); + // the order is important! + iareapanel->setBeforeAfterViews (NULL, iareapanel); + delete iareapanel; + iareapanel = NULL; + + if (beforeIpc) + beforeIpc->stopProcessing (); + + delete beforeIarea; + beforeIarea = NULL; + + if (beforeIpc){ + beforeIpc->setPreviewImageListener (NULL); + } + delete beforePreviewHandler; + beforePreviewHandler = NULL; + if (beforeIpc) + rtengine::StagedImageProcessor::destroy (beforeIpc); + beforeIpc = NULL; + + close (); + + if (epih->pending) + epih->destroyed = true; + else + delete epih; + + delete tpc; + + delete ppframe; + delete leftbox; + delete vboxright; + //delete saveAsDialog; + if(catalogPane) + delete catalogPane; + + if (iTopPanel_1_Show) delete iTopPanel_1_Show; + if (iTopPanel_1_Hide) delete iTopPanel_1_Hide; + if (iHistoryShow) + delete iHistoryShow; + if (iHistoryHide) + delete iHistoryHide; + if(iBeforeLockON) + delete iBeforeLockON; + if(iBeforeLockOFF) + delete iBeforeLockOFF; + if(iRightPanel_1_Show) + delete iRightPanel_1_Show; + if(iRightPanel_1_Hide) + delete iRightPanel_1_Hide; +} + +void EditorPanel::leftPaneButtonReleased(GdkEventButton *event) { + if (event->button == 1) { + // Button 1 released : it's a resize + options.historyPanelWidth = hpanedl->get_position(); + } + /*else if (event->button == 3) { + }*/ +} + +void EditorPanel::rightPaneButtonReleased(GdkEventButton *event) { + if (event->button == 1) { + int winW, winH; + parent->get_size(winW, winH); + // Button 1 released : it's a resize + options.toolPanelWidth = winW - hpanedr->get_position(); + } + /*else if (event->button == 3) { + }*/ +} + +void EditorPanel::writeOptions() { + if (profilep) + profilep->writeOptions(); + if (tpc) + tpc->writeOptions(); +} + +void EditorPanel::showTopPanel(bool show) { + if (tbTopPanel_1->get_active() != show) + tbTopPanel_1->set_active(show); +} + +void EditorPanel::setAspect () { + int winW, winH; + parent->get_size(winW, winH); + hpanedl->set_position(options.historyPanelWidth); + hpanedr->set_position(winW - options.toolPanelWidth); + // initialize components + if (info->get_active() != options.showInfo) + info->set_active (options.showInfo); +} + +void EditorPanel::on_realize () { + realized = true; + Gtk::VBox::on_realize (); + // This line is needed to avoid autoexpansion of the window :-/ + vboxright->set_size_request (options.toolPanelWidth, -1); + tpc->updateToolState(); +} + +void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) { + + close(); + + isProcessing=true; // prevents closing-on-init + + // initialize everything + openThm = tmb; + openThm->increaseRef (); + + fname=openThm->getFileName(); + lastSaveAsFileName = removeExtension (Glib::path_get_basename (fname)); + + previewHandler = new PreviewHandler (); + previewHandler2 = new PreviewHandler (); + + this->isrc = isrc; + ipc = rtengine::StagedImageProcessor::create (isrc); + ipc->setProgressListener (this); + ipc->setPreviewImageListener (previewHandler); + ipc->setPreviewScale (10); // Important + tpc->initImage (ipc, tmb->getType()==FT_Raw); + ipc->setHistogramListener (this); + +// iarea->fitZoom (); // tell to the editorPanel that the next image has to be fitted to the screen + iareapanel->imageArea->setPreviewHandler (previewHandler); + iareapanel->imageArea->setImProcCoordinator (ipc); + navigator->previewWindow->setPreviewHandler (previewHandler); + navigator->previewWindow->setImageArea (iareapanel->imageArea); + + rtengine::ImageSource* is=isrc->getImageSource(); + is->setProgressListener( this ); + + // try to load the last saved parameters from the cache or from the paramfile file + ProcParams* ldprof = openThm->createProcParamsForUpdate(true,false); // will be freed by initProfile + + // initialize profile + Glib::ustring defProf = openThm->getType()==FT_Raw ? options.defProfRaw : options.defProfImg; + profilep->initProfile (defProf, ldprof); + profilep->setInitialFileName (fname); + + openThm->addThumbnailListener (this); + info_toggled (); + + if (beforeIarea) + { + beforeAfterToggled(); + beforeAfterToggled(); + } + + // If in single tab mode, the main crop window is not constructed the very first time + // since there was no resize event + if (iareapanel->imageArea->mainCropWindow) + { + iareapanel->imageArea->mainCropWindow->cropHandler.newImage(ipc, false); + iareapanel->imageArea->mainCropWindow->initialImageArrived(); + + // In single tab mode, the image is not always updated between switches + // normal redraw don't work, so this is the hard way + // Disabled this with Issue 2435 because it seems to work fine now +// if (!options.tabbedUI && iareapanel->imageArea->mainCropWindow->getZoomFitVal() == 1.0) { +// iareapanel->imageArea->mainCropWindow->cropHandler.update(); +// } + } else { + Gtk::Allocation alloc; + iareapanel->imageArea->on_resized(alloc); + } +} + +void EditorPanel::close () { + if (ipc) + { + saveProfile (); + // close image processor and the current thumbnail + tpc->closeImage (); // this call stops image processing + tpc->writeOptions (); + rtengine::ImageSource* is=isrc->getImageSource(); + is->setProgressListener( NULL ); + + if (ipc) { + ipc->setPreviewImageListener (NULL); + } + + if (beforeIpc){ + beforeIpc->setPreviewImageListener (NULL); + } + + delete previewHandler; + previewHandler= NULL; + + if(iareapanel) + { + iareapanel->imageArea->setPreviewHandler (NULL); + iareapanel->imageArea->setImProcCoordinator (NULL); + } + rtengine::StagedImageProcessor::destroy (ipc); + ipc = NULL; + navigator->previewWindow->setPreviewHandler (NULL); + + // If the file was deleted somewhere, the openThm.descreaseRef delete the object, but we don't know here + if (safe_file_test(fname, Glib::FILE_TEST_EXISTS)) { + openThm->removeThumbnailListener (this); + openThm->decreaseRef (); + } + } +} + +void EditorPanel::saveProfile () { + if (!ipc || !openThm) return; + + // If the file was deleted, do not generate ghost entries + if (safe_file_test(fname, Glib::FILE_TEST_EXISTS)) { + ProcParams params; + ipc->getParams (¶ms); + + // Will call updateCache, which will update both the cached and sidecar files if necessary + openThm->setProcParams (params, NULL, EDITOR); +} +} + +Glib::ustring EditorPanel::getShortName () { + if (openThm) return Glib::path_get_basename (openThm->getFileName ()); + else return ""; +} + +Glib::ustring EditorPanel::getFileName () { + if (openThm) return openThm->getFileName (); + else return ""; +} + +// TODO!!! +void EditorPanel::procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) { + +// if (ev!=EvPhotoLoaded) +// saveLabel->set_markup (Glib::ustring("") + M("MAIN_BUTTON_SAVE") + ""); +} + +struct spsparams { + bool inProcessing; + EditorPanelIdleHelper* epih; +}; + +int setProgressStateUIThread (void* data) { + + spsparams* p = static_cast(data); + + if (p->epih->destroyed) { + if (p->epih->pending == 1) + delete p->epih; + else + p->epih->pending--; + delete p; + + return 0; + } + + p->epih->epanel->refreshProcessingState (p->inProcessing); + p->epih->pending--; + delete p; + + return 0; +} + +void EditorPanel::setProgressState (bool inProcessing) { + + epih->pending++; + + spsparams* p = new spsparams; + p->inProcessing = inProcessing; + p->epih = epih; + g_idle_add (setProgressStateUIThread, p); +} + +struct spparams { + double val; + Glib::ustring str; + Gtk::ProgressBar *pProgress; +}; + +int setprogressStrUI( void *p ) +{ + GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected + spparams *s= static_cast(p); + + if( ! s->str.empty() ) + s->pProgress->set_text( M(s->str) ); + if( s->val >=0 ){ + s->pProgress->set_fraction( s->val ); + if( s->val <1.0 ) + s->pProgress->modify_bg( Gtk::STATE_NORMAL,Gdk::Color("red") ); + else + s->pProgress->modify_bg( Gtk::STATE_NORMAL,Gdk::Color("grey") ); + } + + delete s; + return 0; +} + +void EditorPanel::setProgress (double p) +{ + spparams *s=new spparams; + s->val = p; + s->pProgress = progressLabel; + g_idle_add (setprogressStrUI, s); +} + +void EditorPanel::setProgressStr (Glib::ustring str) +{ + spparams *s=new spparams; + s->str = str; + s->val = -1; + s->pProgress = progressLabel; + g_idle_add (setprogressStrUI, s); +} + +// This is only called from the ThreadUI, so within the gtk thread +void EditorPanel::refreshProcessingState (bool inProcessingP) { + spparams *s=new spparams; + s->pProgress = progressLabel; + + if (inProcessingP) { + if (processingStartedTime==0) processingStartedTime = ::time(NULL); + + s->str = "PROGRESSBAR_PROCESSING"; + s->val = 0.0; + } else { + // Set proc params of thumbnail. It saves it into the cache and updates the file browser. + if (ipc && openThm && tpc->getChangedState()) { + rtengine::procparams::ProcParams pparams; + ipc->getParams (&pparams); + openThm->setProcParams (pparams, NULL, EDITOR, false); + } + + // Ring a sound if it was a long event + if (processingStartedTime!=0) { + time_t curTime= ::time(NULL); + if (::difftime(curTime, processingStartedTime) > options.sndLngEditProcDoneSecs) + SoundManager::playSoundAsync(options.sndLngEditProcDone); + + processingStartedTime = 0; + } + + // Set progress bar "done" + s->str = "PROGRESSBAR_READY"; + s->val = 1.0; + +#ifdef WIN32 + // Maybe accessing "parent", which is a Gtk object, can justify to get the Gtk lock... + if (!firstProcessingDone && static_cast(parent)->getIsFullscreen()) { parent->fullscreen(); } +#endif + firstProcessingDone = true; +} + + isProcessing=inProcessingP; + + setprogressStrUI(s); +} + +struct errparams { + Glib::ustring descr; + Glib::ustring title; + EditorPanelIdleHelper* epih; +}; + +void EditorPanel::displayError (Glib::ustring title, Glib::ustring descr) { + GtkWidget* msgd = gtk_message_dialog_new_with_markup (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s", + descr.data()); + gtk_window_set_title((GtkWindow*)msgd, title.data()); + g_signal_connect_swapped (msgd, "response", + G_CALLBACK (gtk_widget_destroy), + msgd); + gtk_widget_show_all (msgd); +} + +int disperrorUI (void* data) { + errparams* p = static_cast(data); + + if (p->epih->destroyed) { + if (p->epih->pending == 1) + delete p->epih; + else + p->epih->pending--; + delete p; + + return 0; + } + + p->epih->epanel->displayError (p->title, p->descr); + p->epih->pending--; + delete p; + + return 0; +} + +void EditorPanel::error (Glib::ustring title, Glib::ustring descr) { + + epih->pending++; + errparams* p = new errparams; + p->descr = descr; + p->title = title; + p->epih = epih; + g_idle_add (disperrorUI, p); +} + +void EditorPanel::info_toggled () { + + Glib::ustring infoString; + Glib::ustring infoString1; //1-st line + Glib::ustring infoString2; //2-nd line + Glib::ustring infoString3; //3-rd line + Glib::ustring infoString4; //4-th line + Glib::ustring expcomp; + + if (!ipc || !openThm) return; + const rtengine::ImageMetaData* idata = ipc->getInitialImage()->getMetaData(); + if (idata && idata->hasExif()){ + infoString1 = Glib::ustring::compose ("%1 + %2", + Glib::ustring(idata->getMake()+" "+idata->getModel()), + Glib::ustring(idata->getLens())); + + infoString2 = Glib::ustring::compose ("f/%1 %2s %3%4 %5mm", + Glib::ustring(idata->apertureToString(idata->getFNumber())), + Glib::ustring(idata->shutterToString(idata->getShutterSpeed())), + M("QINFO_ISO"), idata->getISOSpeed(), + Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), idata->getFocalLen())); + + expcomp = Glib::ustring(idata->expcompToString(idata->getExpComp(),true)); // maskZeroexpcomp + if (expcomp!=""){ + infoString2 = Glib::ustring::compose("%1 %2EV", + infoString2, + expcomp /*Glib::ustring(idata->expcompToString(idata->getExpComp()))*/); + } + + infoString3 = Glib::ustring::compose ("%1%2", + escapeHtmlChars(Glib::path_get_dirname(openThm->getFileName())) + G_DIR_SEPARATOR_S, + escapeHtmlChars(Glib::path_get_basename(openThm->getFileName())) ); + + int ww= ipc->getFullWidth(); + int hh= ipc->getFullHeight(); + //megapixels + infoString4 = Glib::ustring::compose ("%1 MP (%2x%3)", Glib::ustring::format(std::setw(4), std::fixed, std::setprecision(1), (float)ww*hh/1000000), ww, hh); + + infoString = Glib::ustring::compose ("%1\n%2\n%3\n%4",infoString1, infoString2, infoString3, infoString4); + } + else + infoString = M("QINFO_NOEXIF"); + + iareapanel->imageArea->setInfoText (infoString); + iareapanel->imageArea->infoEnabled (info->get_active ()); +} + +void EditorPanel::hideHistoryActivated () { + + removeIfThere (hpanedl, leftbox, false); + if (hidehp->get_active()) + hpanedl->pack1 (*leftbox, false, true); + options.showHistory = hidehp->get_active(); + + if (options.showHistory){ + hidehp->set_image (*iHistoryHide); + } + else { + hidehp->set_image (*iHistoryShow); + } + + tbShowHideSidePanels_managestate(); +} + + +void EditorPanel::tbRightPanel_1_toggled () { +/* + removeIfThere (hpanedr, vboxright, false); + if (tbRightPanel_1->get_active()){ + hpanedr->pack2(*vboxright, false, true); + tbRightPanel_1->set_image (*iRightPanel_1_Hide); + } + else { + tbRightPanel_1->set_image (*iRightPanel_1_Show); + } + tbShowHideSidePanels_managestate(); + */ + if (vboxright){ + if (tbRightPanel_1->get_active()){ + vboxright->show(); + tbRightPanel_1->set_image (*iRightPanel_1_Hide); + } + else{ + vboxright->hide(); + tbRightPanel_1->set_image (*iRightPanel_1_Show); + } + tbShowHideSidePanels_managestate(); + } +} + +void EditorPanel::tbTopPanel_1_visible (bool visible){ + if (!tbTopPanel_1) + return; + + if (visible) + tbTopPanel_1->show(); + else + tbTopPanel_1->hide(); +} + +void EditorPanel::tbTopPanel_1_toggled () { + + if (catalogPane){ // catalogPane does not exist in multitab mode + + if (tbTopPanel_1->get_active()){ + catalogPane->show(); + tbTopPanel_1->set_image (*iTopPanel_1_Hide); + options.editorFilmStripOpened = true; + } + else { + catalogPane->hide(); + tbTopPanel_1->set_image (*iTopPanel_1_Show); + options.editorFilmStripOpened = false; + } + + tbShowHideSidePanels_managestate(); + } +} + +/* + * WARNING: Take care of the simpleEditor value when adding or modifying shortcut keys, + * since handleShortcutKey is now also triggered in simple editor mode + */ +bool EditorPanel::handleShortcutKey (GdkEventKey* event) { + + bool ctrl = event->state & GDK_CONTROL_MASK; + bool shift = event->state & GDK_SHIFT_MASK; + bool alt = event->state & GDK_MOD1_MASK; +#ifdef __WIN32__ + bool altgr = event->state & GDK_MOD2_MASK; +#else + bool altgr = event->state & GDK_MOD5_MASK; +#endif + + // Editor Layout + switch(event->keyval) { + case GDK_L: + if (tbTopPanel_1) + tbTopPanel_1->set_active (!tbTopPanel_1->get_active()); // toggle top panel + if (ctrl) hidehp->set_active (!hidehp->get_active()); // toggle History (left panel) + if (alt) tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); // toggle right panel + return true; + break; + case GDK_l: + if (!shift && !alt /*&& !ctrl*/){ + hidehp->set_active (!hidehp->get_active()); // toggle History (left panel) + return true; + } + if (alt && !ctrl){ // toggle right panel + tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); + return true; + } + if (alt && ctrl){ // toggle left and right panels + hidehp->set_active (!hidehp->get_active()); + tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); + return true; + } + break; + case GDK_m: // Maximize preview panel: hide top AND right AND history panels + if (!ctrl && !alt) { + toggleSidePanels(); + return true; + } + break; + case GDK_M: // Maximize preview panel: hide top AND right AND history panels AND (fit image preview) + if (!ctrl && !alt) { + toggleSidePanelsZoomFit(); + return true; + } + break; + } +#ifdef __WIN32__ + if (!alt && !ctrl && !altgr && event->hardware_keycode == 0x39 ) { + iareapanel->imageArea->previewModePanel->togglebackColor(); + return true; + } +#else + if (!alt && !ctrl && !altgr && event->hardware_keycode == 0x12 ) { + iareapanel->imageArea->previewModePanel->togglebackColor(); + return true; + } +#endif + if (!alt){ + if (!ctrl) { + // Normal + switch(event->keyval) { + case GDK_bracketright: + tpc->coarse->rotateRight(); + return true; + case GDK_bracketleft: + tpc->coarse->rotateLeft(); + return true; + case GDK_i: + case GDK_I: + info->set_active (!info->get_active()); + return true; + case GDK_B: + beforeAfter->set_active (!beforeAfter->get_active()); + return true; + case GDK_plus: + case GDK_equal: + case GDK_KP_Add: + iareapanel->imageArea->zoomPanel->zoomInClicked(); + return true; + case GDK_minus: + case GDK_underscore: + case GDK_KP_Subtract: + iareapanel->imageArea->zoomPanel->zoomOutClicked(); + return true; + case GDK_z://GDK_1 + iareapanel->imageArea->zoomPanel->zoom11Clicked(); + return true; +/* +#ifndef __WIN32__ + case GDK_9: // toggle background color of the preview + iareapanel->imageArea->previewModePanel->togglebackColor(); + return true; +#endif +*/ + case GDK_r: //preview mode Red + iareapanel->imageArea->previewModePanel->toggleR(); + return true; + case GDK_g: //preview mode Green + iareapanel->imageArea->previewModePanel->toggleG(); + return true; + case GDK_b: //preview mode Blue + iareapanel->imageArea->previewModePanel->toggleB(); + return true; + case GDK_v: //preview mode Luminosity + iareapanel->imageArea->previewModePanel->toggleL(); + return true; + case GDK_F: //preview mode Focus Mask + iareapanel->imageArea->previewModePanel->toggleFocusMask(); + return true; + + case GDK_f: + iareapanel->imageArea->zoomPanel->zoomFitClicked(); + return true; + case GDK_less: + iareapanel->imageArea->indClippedPanel->toggleClipped(true); + return true; + case GDK_greater: + iareapanel->imageArea->indClippedPanel->toggleClipped(false); + return true; + + case GDK_F5: + openThm->openDefaultViewer((event->state & GDK_SHIFT_MASK) ? 2 : 1); + return true; + case GDK_y: // synchronize filebrowser with image in Editor + if (!simpleEditor && fPanel && !fname.empty()){ + fPanel->fileCatalog->selectImage(fname, false); + return true; + } + break; // to avoid gcc complain + case GDK_x: // clear filters and synchronize filebrowser with image in Editor + if (!simpleEditor && fPanel && !fname.empty()){ + fPanel->fileCatalog->selectImage(fname, true); + return true; + } + break; // to avoid gcc complain + } + } + else { + // With control + switch (event->keyval) { + case GDK_S: + saveProfile(); + setProgressStr(M("PROGRESSBAR_PROCESSING_PROFILESAVED")); + return true; + case GDK_s: + saveAsPressed(); + return true; + case GDK_b: + if (!simpleEditor) + queueImgPressed(); + return true; + case GDK_e: + sendToGimpPressed(); + return true; + case GDK_z: + history->undo (); + return true; + case GDK_Z: + history->redo (); + return true; + case GDK_F5: + openThm->openDefaultViewer(3); + return true; + } + } //if (!ctrl) + } //if (!alt) + + if (alt){ + switch (event->keyval) { + case GDK_s: + history->addBookmarkPressed (); + setProgressStr(M("PROGRESSBAR_SNAPSHOT_ADDED")); + return true; + case GDK_f: + iareapanel->imageArea->zoomPanel->zoomFitCropClicked(); + return true; + } + } + + if (shift){ + switch (event->keyval) { + case GDK_F3: // open Previous image from Editor's perspective + if (!simpleEditor && fPanel && !fname.empty()){ + EditorPanel::openPreviousEditorImage(); + return true; + } + break; // to avoid gcc complain + case GDK_F4: // open next image from Editor's perspective + if (!simpleEditor && fPanel && !fname.empty()){ + EditorPanel::openNextEditorImage(); + return true; + } + break; // to avoid gcc complain + } + } + + if(tpc->getToolBar() && tpc->getToolBar()->handleShortcutKey(event)) + return true; + if(tpc->handleShortcutKey(event)) + return true; + + if (!simpleEditor && fPanel){ + if (fPanel->handleShortcutKey(event)) + return true; + } + + return false; +} + +void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt) { + + if (whoChangedIt!=EDITOR) { + PartialProfile pp(true); + pp.set(true); + *(pp.pparams) = openThm->getProcParams(); + tpc->profileChange (&pp, rtengine::EvProfileChangeNotification, M("PROGRESSDLG_PROFILECHANGEDINBROWSER")); + pp.deleteInstance(); + } +} + +bool EditorPanel::idle_saveImage (ProgressConnector *pc, Glib::ustring fname, SaveFormat sf) { + rtengine::IImage16* img = pc->returnValue(); + delete pc; + if( img ) { + setProgressStr(M("GENERAL_SAVE")); setProgress(0.9f); + + ProgressConnector *ld = new ProgressConnector(); + img->setSaveProgressListener (parent->getProgressListener()); + if (sf.format=="tif") + ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsTIFF), fname, sf.tiffBits, sf.tiffUncompressed), + sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fname, sf)); + else if (sf.format=="png") + ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsPNG), fname, sf.pngCompression, sf.pngBits), + sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fname, sf)); + else if (sf.format=="jpg") + ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsJPEG), fname, sf.jpegQuality, sf.jpegSubSamp), + sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fname, sf)); + } else { + Glib::ustring msg_ = Glib::ustring("") + fname + ": Error during image processing\n"; + Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd.run (); + + saveimgas->set_sensitive(true); + sendtogimp->set_sensitive(true); + isProcessing = false; + + } + rtengine::ImageSource* imgsrc = isrc->getImageSource (); + imgsrc->setProgressListener(this); + return false; +} + +bool EditorPanel::idle_imageSaved(ProgressConnector *pc,rtengine::IImage16* img,Glib::ustring fname, SaveFormat sf){ + img->free (); + + if (! pc->returnValue() ) { + openThm->imageDeveloped (); + // save processing parameters, if needed + if (sf.saveParams) { + rtengine::procparams::ProcParams pparams; + ipc->getParams (&pparams); + // We keep the extension to avoid overwriting the profile when we have + // the same output filename with different extension + //pparams.save (removeExtension (fname) + ".out" + paramFileExtension); + pparams.save (fname + ".out" + paramFileExtension); + } + } else { + error(M("MAIN_MSG_CANNOTSAVE"), fname); + } + + saveimgas->set_sensitive(true); + sendtogimp->set_sensitive(true); + + parent->setProgressStr(""); + parent->setProgress(0.); + + setProgressState(false); + + delete pc; + SoundManager::playSoundAsync(options.sndBatchQueueDone); + isProcessing = false; + return false; +} + +BatchQueueEntry* EditorPanel::createBatchQueueEntry () { + + rtengine::procparams::ProcParams pparams; + ipc->getParams (&pparams); + //rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); + rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (openThm->getFileName (), openThm->getType()==FT_Raw, pparams); + int fullW=0, fullH=0; + isrc->getImageSource()->getFullSize(fullW, fullH, pparams.coarse.rotate==90 || pparams.coarse.rotate==270 ? TR_R90 : TR_NONE); + int prevh = BatchQueue::calcMaxThumbnailHeight(); + int prevw = int((size_t)fullW * (size_t)prevh / (size_t)fullH); + return new BatchQueueEntry (job, pparams, openThm->getFileName(), prevw, prevh, openThm); +} + + + +void EditorPanel::saveAsPressed () { + if (!ipc || !openThm) return; + bool fnameOK = false; + Glib::ustring fnameOut; + + SaveAsDialog* saveAsDialog; + if (safe_file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR)) + saveAsDialog = new SaveAsDialog (options.lastSaveAsPath); + else + saveAsDialog = new SaveAsDialog (safe_get_user_picture_dir()); + + saveAsDialog->set_default_size (options.saveAsDialogWidth, options.saveAsDialogHeight); + saveAsDialog->setInitialFileName (lastSaveAsFileName); + saveAsDialog->setImagePath (fname); + + do { + int result = saveAsDialog->run (); + + // The SaveAsDialog ensure that a filename has been specified + fnameOut = saveAsDialog->getFileName (); + + options.lastSaveAsPath = saveAsDialog->getDirectory (); + options.saveAsDialogWidth = saveAsDialog->get_width (); + options.saveAsDialogHeight = saveAsDialog->get_height (); + options.autoSuffix = saveAsDialog->getAutoSuffix (); + options.saveMethodNum = saveAsDialog->getSaveMethodNum (); + lastSaveAsFileName = Glib::path_get_basename (removeExtension (fnameOut)); + SaveFormat sf = saveAsDialog->getFormat (); + options.saveFormat = sf; + options.forceFormatOpts = saveAsDialog->getForceFormatOpts (); + + if (result != Gtk::RESPONSE_OK) + break; + + if (saveAsDialog->getImmediately ()) { + // separate filename and the path to the destination directory + Glib::ustring dstdir = Glib::path_get_dirname (fnameOut); + Glib::ustring dstfname = Glib::path_get_basename (removeExtension(fnameOut)); + Glib::ustring dstext = getExtension (fnameOut); + + if (saveAsDialog->getAutoSuffix()) { + + Glib::ustring fnameTemp; + for (int tries=0; tries<100; tries++) { + if (tries==0) + fnameTemp = Glib::ustring::compose ("%1.%2", Glib::build_filename (dstdir, dstfname), dstext); + else + fnameTemp = Glib::ustring::compose ("%1-%2.%3", Glib::build_filename (dstdir, dstfname), tries, dstext); + + if (!safe_file_test (fnameTemp, Glib::FILE_TEST_EXISTS)) { + fnameOut = fnameTemp; + fnameOK = true; + break; + } + } + } + // check if it exists + if (!fnameOK) { + fnameOK = confirmOverwrite (*saveAsDialog, fnameOut); + } + + if (fnameOK) { + isProcessing = true; + // save image + rtengine::procparams::ProcParams pparams; + ipc->getParams (&pparams); + rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); + + ProgressConnector *ld = new ProgressConnector(); + ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener(), options.tunnelMetaData, false ), + sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_saveImage ),ld,fnameOut,sf )); + saveimgas->set_sensitive(false); + sendtogimp->set_sensitive(false); + } + } + else { + BatchQueueEntry* bqe = createBatchQueueEntry (); + bqe->outFileName = fnameOut; + bqe->saveFormat = saveAsDialog->getFormat (); + bqe->forceFormatOpts = saveAsDialog->getForceFormatOpts (); + parent->addBatchQueueJob (bqe, saveAsDialog->getToHeadOfQueue ()); + fnameOK = true; + } + // ask parent to redraw file browser + // ... or does it automatically when the tab is switched to it + } while (!fnameOK); + + saveAsDialog->hide(); +} + +void EditorPanel::queueImgPressed () { + if (!ipc || !openThm) return; + saveProfile (); + parent->addBatchQueueJob (createBatchQueueEntry ()); +} + +void EditorPanel::sendToGimpPressed () { + if (!ipc || !openThm) return; + // develop image + rtengine::procparams::ProcParams pparams; + ipc->getParams (&pparams); + rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); + ProgressConnector *ld = new ProgressConnector(); + ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener(), options.tunnelMetaData, false ), + sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_sendToGimp ),ld, openThm->getFileName() )); + saveimgas->set_sensitive(false); + sendtogimp->set_sensitive(false); +} + + +void EditorPanel::openPreviousEditorImage() { + if (!simpleEditor && fPanel && !fname.empty()) + fPanel->fileCatalog->openNextPreviousEditorImage(fname, false, NAV_PREVIOUS); +} + +void EditorPanel::openNextEditorImage() { + if (!simpleEditor && fPanel && !fname.empty()) + fPanel->fileCatalog->openNextPreviousEditorImage(fname, false, NAV_NEXT); +} + +void EditorPanel::syncFileBrowser() { // synchronize filebrowser with image in Editor + if (!simpleEditor && fPanel && !fname.empty()) + fPanel->fileCatalog->selectImage(fname, false); +} + +bool EditorPanel::idle_sendToGimp( ProgressConnector *pc, Glib::ustring fname){ + + rtengine::IImage16* img = pc->returnValue(); + delete pc; + if (img) { + // get file name base + Glib::ustring shortname = removeExtension (Glib::path_get_basename (fname)); + Glib::ustring dirname = Glib::get_tmp_dir (); + Glib::ustring fname = Glib::build_filename (dirname, shortname); + + SaveFormat sf; + sf.format = "tif"; + sf.tiffBits = 16; + sf.tiffUncompressed = true; + sf.saveParams = true; + + Glib::ustring fileName = Glib::ustring::compose ("%1.%2", fname, sf.format); + + int tries = 1; + while (safe_file_test (fileName, Glib::FILE_TEST_EXISTS) && tries<1000) { + fileName = Glib::ustring::compose("%1-%2.%3", fname, tries, sf.format); + tries++; + } + if (tries==1000){ + img->free (); + return false; + } + + ProgressConnector *ld = new ProgressConnector(); + img->setSaveProgressListener (parent->getProgressListener()); + ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsTIFF), fileName, sf.tiffBits, sf.tiffUncompressed), + sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_sentToGimp), ld, img, fileName)); + }else{ + Glib::ustring msg_ = Glib::ustring(" Error during image processing\n"); + Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd.run (); + saveimgas->set_sensitive(true); + sendtogimp->set_sensitive(true); + } + return false; +} + +bool EditorPanel::idle_sentToGimp(ProgressConnector *pc,rtengine::IImage16* img,Glib::ustring filename){ + img->free (); + int errore = pc->returnValue(); + delete pc; + if (!errore) { + saveimgas->set_sensitive(true); + sendtogimp->set_sensitive(true); + parent->setProgressStr(""); + parent->setProgress(0.); + bool success=false; + Glib::ustring cmdLine; + Glib::ustring executable; + // start gimp + if (options.editorToSendTo==1) { +#ifdef WIN32 + executable = Glib::build_filename (Glib::build_filename(options.gimpDir,"bin"), "gimp-win-remote"); + cmdLine = Glib::ustring("\"") + executable + Glib::ustring("\" gimp-2.4.exe ") + Glib::ustring("\"") + filename + Glib::ustring("\""); + if ( safe_file_test(executable, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) { + success = safe_spawn_command_line_async (cmdLine); + } +#elif defined __APPLE__ + cmdLine = Glib::ustring("open -a /Applications/GIMP.app \'") + filename + Glib::ustring("\'"); + success = safe_spawn_command_line_async (cmdLine); + std::cout << cmdLine << std::endl; +#else + cmdLine = Glib::ustring("gimp \"") + filename + Glib::ustring("\""); + success = safe_spawn_command_line_async (cmdLine); + std::cout << cmdLine << std::endl; +#endif + if (!success){ +#ifdef WIN32 + int ver = 12; + while (!success && ver) { + executable = Glib::build_filename (Glib::build_filename(options.gimpDir,"bin"), Glib::ustring::compose(Glib::ustring("gimp-2.%1.exe"),ver)); + if ( safe_file_test(executable, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) { + cmdLine = Glib::ustring("\"") + executable + Glib::ustring("\" \"") + filename + Glib::ustring("\""); + success = safe_spawn_command_line_async (cmdLine); + } + ver--; + } +#elif defined __APPLE__ + cmdLine = Glib::ustring("open -a /Applications/Gimp.app/Contents/Resources/start \'") + filename + Glib::ustring("\'"); + success = safe_spawn_command_line_async (cmdLine); + std::cout << cmdLine << std::endl; +#else + cmdLine = Glib::ustring("gimp-remote \"") + filename + Glib::ustring("\""); + success = safe_spawn_command_line_async (cmdLine); + std::cout << cmdLine << std::endl; +#endif + } + } + else if (options.editorToSendTo==2) { +#ifdef WIN32 + executable = Glib::build_filename(options.psDir,"Photoshop.exe"); + if ( safe_file_test(executable, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) { + cmdLine = Glib::ustring("\"") + executable + Glib::ustring("\" \"") + filename + Glib::ustring("\""); + success = safe_spawn_command_line_async (cmdLine); + } +#else + #ifdef __APPLE__ + cmdLine = Glib::ustring("open -a \'") + Glib::build_filename(options.psDir,"Photoshop.app\' ") + Glib::ustring("\'") + filename + Glib::ustring("\'"); + #else + cmdLine = Glib::ustring("\"") + Glib::build_filename(options.psDir,"Photoshop.exe") + Glib::ustring("\" \"") + filename + Glib::ustring("\""); + #endif + success = safe_spawn_command_line_async (cmdLine); + std::cout << cmdLine << std::endl; +#endif + } + else if (options.editorToSendTo==3) { +#ifdef WIN32 + if ( safe_file_test(options.customEditorProg, (Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)) ) { + cmdLine = Glib::ustring("\"") + options.customEditorProg + Glib::ustring("\" \"") + filename + Glib::ustring("\""); + success = safe_spawn_command_line_async (cmdLine); + } +#else + #ifdef __APPLE__ + cmdLine = options.customEditorProg + Glib::ustring(" \"") + filename + Glib::ustring("\""); + #else + cmdLine = Glib::ustring("\"") + options.customEditorProg + Glib::ustring("\" \"") + filename + Glib::ustring("\""); + #endif + success = safe_spawn_command_line_async (cmdLine); + std::cout << cmdLine << std::endl; +#endif + } + + if (!success) { + Gtk::MessageDialog* msgd = new Gtk::MessageDialog (*parent, M("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd->set_secondary_text (M("MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY")); + msgd->set_title (M("MAIN_BUTTON_SENDTOEDITOR")); + msgd->run (); + delete msgd; + } + + } + + return false; +} + +void EditorPanel::historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) { + + if (beforeIpc) { + ProcParams* pparams = beforeIpc->beginUpdateParams (); + *pparams = params; + beforeIpc->endUpdateParams (rtengine::EvProfileChanged); // starts the IPC processing + } +} + +void EditorPanel::beforeAfterToggled () { + + if(!ipc) + return; + + removeIfThere (beforeAfterBox, beforeBox, false); + removeIfThere (afterBox, afterHeaderBox, false); + if (beforeIarea) { + if (beforeIpc) + beforeIpc->stopProcessing (); + iareapanel->setBeforeAfterViews (NULL, iareapanel); + iareapanel->imageArea->iLinkedImageArea = NULL; + delete beforeIarea; + beforeIarea = NULL; + if (beforeIpc) + { beforeIpc->setPreviewImageListener (NULL); + } + delete beforePreviewHandler; + beforePreviewHandler = NULL; + if (beforeIpc) + rtengine::StagedImageProcessor::destroy (beforeIpc); + beforeIpc = NULL; + } + + if (beforeAfter->get_active ()) { + + int errorCode=0; + rtengine::InitialImage *beforeImg = rtengine::InitialImage::load ( isrc->getImageSource ()->getFileName(), openThm->getType()==FT_Raw , &errorCode, NULL); + if( !beforeImg || errorCode ) + return; + + beforeIarea = new ImageAreaPanel (); + + int HeaderBoxHeight = 17; + + beforeLabel = Gtk::manage (new Gtk::Label ()); + beforeLabel->set_markup (Glib::ustring("") + M("GENERAL_BEFORE") + ""); + tbBeforeLock = Gtk::manage (new Gtk::ToggleButton ()); + tbBeforeLock->set_tooltip_markup (M("MAIN_TOOLTIP_BEFOREAFTERLOCK")); + tbBeforeLock->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::tbBeforeLock_toggled) ); + beforeHeaderBox = Gtk::manage (new Gtk::HBox ()); + beforeHeaderBox->pack_end (*tbBeforeLock, Gtk::PACK_SHRINK, 2); + beforeHeaderBox->pack_end (*beforeLabel, Gtk::PACK_SHRINK, 2); + beforeHeaderBox->set_size_request(0, HeaderBoxHeight); + + history->blistenerLock ? tbBeforeLock->set_image (*iBeforeLockON):tbBeforeLock->set_image (*iBeforeLockOFF); + tbBeforeLock->set_active(history->blistenerLock); + + beforeBox = Gtk::manage (new Gtk::VBox ()); + beforeBox->pack_start (*beforeHeaderBox, Gtk::PACK_SHRINK, 2); + beforeBox->pack_start (*beforeIarea); + + afterLabel = Gtk::manage (new Gtk::Label ()); + afterLabel->set_markup (Glib::ustring("") + M("GENERAL_AFTER") + ""); + afterHeaderBox = Gtk::manage (new Gtk::HBox ()); + afterHeaderBox->set_size_request(0, HeaderBoxHeight); + afterHeaderBox->pack_end (*afterLabel, Gtk::PACK_SHRINK, 2); + afterBox->pack_start (*afterHeaderBox, Gtk::PACK_SHRINK, 2); + afterBox->reorder_child (*afterHeaderBox, 0); + + beforeAfterBox->pack_start (*beforeBox); + beforeAfterBox->reorder_child (*beforeBox, 0); + beforeAfterBox->show_all (); + + beforePreviewHandler = new PreviewHandler (); + + beforeIpc = rtengine::StagedImageProcessor::create (beforeImg); + beforeIpc->setPreviewScale (10); + beforeIpc->setPreviewImageListener (beforePreviewHandler); + beforeIarea->imageArea->setPreviewHandler (beforePreviewHandler); + beforeIarea->imageArea->setImProcCoordinator (beforeIpc); + + beforeIarea->imageArea->setPreviewModePanel(iareapanel->imageArea->previewModePanel); + beforeIarea->imageArea->setIndicateClippedPanel(iareapanel->imageArea->indClippedPanel); + iareapanel->imageArea->iLinkedImageArea = beforeIarea->imageArea; + + iareapanel->setBeforeAfterViews (beforeIarea, iareapanel); + beforeIarea->setBeforeAfterViews (beforeIarea, iareapanel); + + rtengine::procparams::ProcParams params; + if (history->getBeforeLineParams (params)) + historyBeforeLineChanged (params); + } +} + +void EditorPanel::tbBeforeLock_toggled () { + history->blistenerLock = tbBeforeLock->get_active(); + tbBeforeLock->get_active()? tbBeforeLock->set_image (*iBeforeLockON) : tbBeforeLock->set_image (*iBeforeLockOFF); +} + +void EditorPanel::histogramChanged (LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve, /*LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, + LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw , LUTu & histChroma) { + + if (histogramPanel) histogramPanel->histogramChanged (histRed, histGreen, histBlue, histLuma, histRedRaw, histGreenRaw, histBlueRaw, histChroma); + tpc->updateCurveBackgroundHistogram (histToneCurve, histLCurve, histCCurve,/*histCLurve, histLLCurve,*/ histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma); +} + +bool EditorPanel::CheckSidePanelsVisibility() { + if (tbTopPanel_1) { + if(tbTopPanel_1->get_active()==false && tbRightPanel_1->get_active()==false && hidehp->get_active()==false) + return false; + return true; + } + if(tbRightPanel_1->get_active()==false && hidehp->get_active()==false) + return false; + return true; +} +void EditorPanel::toggleSidePanels(){ + // Maximize preview panel: + // toggle top AND right AND history panels + + bool bAllSidePanelsVisible; + bAllSidePanelsVisible= CheckSidePanelsVisibility(); + + if (tbTopPanel_1) + tbTopPanel_1->set_active (!bAllSidePanelsVisible); + tbRightPanel_1->set_active (!bAllSidePanelsVisible); + hidehp->set_active (!bAllSidePanelsVisible); + if (bAllSidePanelsVisible == false) + tbShowHideSidePanels->set_image (*iShowHideSidePanels); + else + tbShowHideSidePanels->set_image (*iShowHideSidePanels_exit); +} + +void EditorPanel::toggleSidePanelsZoomFit() { + toggleSidePanels(); + + // fit image preview + // !!! TODO this does not want to work... seems to have an effect on a subsequent key press + // iarea->imageArea->zoomPanel->zoomFitClicked(); +} + +void EditorPanel::tbShowHideSidePanels_managestate() { + bool bAllSidePanelsVisible; + bAllSidePanelsVisible = CheckSidePanelsVisibility(); + ShowHideSidePanelsconn.block (true); + + tbShowHideSidePanels->set_active (!bAllSidePanelsVisible); + + ShowHideSidePanelsconn.block (false); +} + +void EditorPanel::updateTPVScrollbar (bool hide) { + tpc->updateTPVScrollbar (hide); +} + +void EditorPanel::updateTabsUsesIcons (bool useIcons) { + tpc->updateTabsUsesIcons (useIcons); +} + +void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition) { + + switch (newPosition) { + case 0: + // No histogram + if (!oldPosition) { + // An histogram actually exist, we delete it + if (oldPosition == 1) + removeIfThere(leftbox, histogramPanel, false); + else if (oldPosition == 2) + removeIfThere(vboxright, histogramPanel, false); + delete histogramPanel; + histogramPanel = NULL; + } + // else no need to create it + break; + case 1: + // Histogram on the left pane + if (oldPosition == 0) { + // There was no Histogram before, so we create it + histogramPanel = Gtk::manage (new HistogramPanel ()); + leftbox->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2); + } + else if (oldPosition == 2) { + // The histogram was on the right side, so we move it to the left + histogramPanel->reference(); + removeIfThere(vboxright, histogramPanel, false); + leftbox->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2); + histogramPanel->unreference(); + } + histogramPanel->reorder(Gtk::ALIGN_LEFT); + leftbox->reorder_child(*histogramPanel, 0); + break; + case 2: + default: + // Histogram on the right pane + if (oldPosition == 0) { + // There was no Histogram before, so we create it + histogramPanel = Gtk::manage (new HistogramPanel ()); + vboxright->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2); + } + else if (oldPosition == 1) { + // The histogram was on the left side, so we move it to the right + histogramPanel->reference(); + removeIfThere(leftbox, histogramPanel, false); + vboxright->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2); + histogramPanel->unreference(); + } + histogramPanel->reorder(Gtk::ALIGN_RIGHT); + vboxright->reorder_child(*histogramPanel, 0); + break; + } + + iareapanel->imageArea->setPointerMotionHListener (histogramPanel); +} diff --git a/rtgui/editwindow.cc b/rtgui/editwindow.cc index af0e722ac..c57898da2 100644 --- a/rtgui/editwindow.cc +++ b/rtgui/editwindow.cc @@ -1,243 +1,243 @@ -/* -* This file is part of RawTherapee. -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -*/ - -#include "editwindow.h" -#include "options.h" -#include "preferences.h" -#include "cursormanager.h" -#include "rtwindow.h" -#include -#include "rtimage.h" -#include "threadutils.h" - -static EditWindow* editWnd = NULL; - -// Check if the system has more than one display and option is set -bool EditWindow::isMultiDisplayEnabled() { - return options.multiDisplayMode>0 && Gdk::Screen::get_default()->get_n_monitors ()>1; -} - -// Should only be created once, auto-creates window on correct display -EditWindow* EditWindow::getInstance(RTWindow* p) -{ - - if (editWnd == NULL) { - static MyMutex smutex_; - MyMutex::MyLock lock(smutex_); - if ( editWnd == 0 ) { - editWnd = new EditWindow(p); - - // Determine the other display and maximize the window on that - const Glib::RefPtr< Gdk::Window >& wnd=p->get_window(); - int monNo=p->get_screen()->get_monitor_at_window (wnd); - +/* +* This file is part of RawTherapee. +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ + +#include "editwindow.h" +#include "options.h" +#include "preferences.h" +#include "cursormanager.h" +#include "rtwindow.h" +#include +#include "rtimage.h" +#include "threadutils.h" + +static EditWindow* editWnd = NULL; + +// Check if the system has more than one display and option is set +bool EditWindow::isMultiDisplayEnabled() { + return options.multiDisplayMode>0 && Gdk::Screen::get_default()->get_n_monitors ()>1; +} + +// Should only be created once, auto-creates window on correct display +EditWindow* EditWindow::getInstance(RTWindow* p) +{ + + if (editWnd == NULL) { + static MyMutex smutex_; + MyMutex::MyLock lock(smutex_); + if ( editWnd == 0 ) { + editWnd = new EditWindow(p); + + // Determine the other display and maximize the window on that + const Glib::RefPtr< Gdk::Window >& wnd=p->get_window(); + int monNo=p->get_screen()->get_monitor_at_window (wnd); + Gdk::Rectangle lMonitorRect; - editWnd->get_screen()->get_monitor_geometry(isMultiDisplayEnabled() ? (monNo==0 ? 1 : 0) : monNo, lMonitorRect); - editWnd->move(lMonitorRect.get_x(), lMonitorRect.get_y()); - editWnd->maximize(); - editWnd->show(); - } else { - editWnd->show_all(); - } - } - - return editWnd; -} - -EditWindow::EditWindow (RTWindow* p) : parent(p) , isFullscreen(false) { - - Glib::ustring fName = "rt-logo.png"; - Glib::ustring fullPath = RTImage::findIconAbsolutePath(fName); - -#ifdef GLIBMM_EXCEPTIONS_ENABLED - try { set_default_icon_from_file (fullPath); - } catch(Glib::Exception& ex) { printf ("%s\n", ex.what().c_str()); } -#else - { std::auto_ptr error; - set_default_icon_from_file (fullPath, error); - } -#endif //GLIBMM_EXCEPTIONS_ENABLED - set_title_decorated(""); - property_allow_shrink() = true; - set_modal(false); - set_resizable(true); - - property_destroy_with_parent().set_value(false); - signal_window_state_event().connect( sigc::mem_fun(*this, &EditWindow::on_window_state_event) ); - - mainNB = Gtk::manage (new Gtk::Notebook ()); - mainNB->set_scrollable (true); - mainNB->signal_switch_page().connect_notify( sigc::mem_fun(*this, &EditWindow::on_mainNB_switch_page) ); - - signal_key_press_event().connect( sigc::mem_fun(*this, &EditWindow::keyPressed) ); - - Gtk::VBox* mainBox = Gtk::manage (new Gtk::VBox ()); - mainBox->pack_start (*mainNB); - - add (*mainBox); - show_all (); -} - -void EditWindow::on_realize () { - Gtk::Window::on_realize (); - - cursorManager.init (get_window()); -} - -bool EditWindow::on_window_state_event(GdkEventWindowState* event) { - if (!event->new_window_state) { - // Window mode - options.windowMaximized = false; - } - else if (event->new_window_state & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN)) { - // Fullscreen mode - options.windowMaximized = true; - } - return true; -} - -void EditWindow::on_mainNB_switch_page(GtkNotebookPage* page, guint page_num) { - //if (page_num > 1) { - EditorPanel *ep = static_cast(mainNB->get_nth_page(page_num)); - - if (mainNB->get_n_pages()>1 && page_num<=(filesEdited.size()-1)){ - set_title_decorated(ep->getFileName()); - } - ep->setAspect(); - //} -} - -void EditWindow::addEditorPanel (EditorPanel* ep, const std::string &name) { - ep->setParent (parent); - - // construct closeable tab for the image - Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ()); - hb->pack_start (*Gtk::manage (new RTImage ("rtwindow.png"))); - hb->pack_start (*Gtk::manage (new Gtk::Label (Glib::path_get_basename (name)))); - hb->set_tooltip_markup (name); - Gtk::Button* closeb = Gtk::manage (new Gtk::Button ()); - closeb->set_image (*Gtk::manage(new RTImage ("gtk-close.png"))); - closeb->set_relief (Gtk::RELIEF_NONE); - closeb->set_focus_on_click (false); - // make the button as small as possible - Glib::RefPtr style = Gtk::RcStyle::create (); - style->set_xthickness (0); - style->set_ythickness (0); - - closeb->modify_style (style); - closeb->signal_clicked().connect( sigc::bind (sigc::mem_fun(*this, &EditWindow::remEditorPanel) , ep)); - hb->pack_end (*closeb); - hb->set_spacing (2); - hb->show_all (); - - mainNB->append_page (*ep, *hb); - mainNB->set_current_page (mainNB->page_num (*ep)); - mainNB->set_tab_reorderable (*ep, true); - - set_title_decorated(name); - - epanels[ name ] = ep; - filesEdited.insert ( name ); - parent->fpanel->refreshEditedState (filesEdited); - ep->setAspect(); -} - + editWnd->get_screen()->get_monitor_geometry(isMultiDisplayEnabled() ? (monNo==0 ? 1 : 0) : monNo, lMonitorRect); + editWnd->move(lMonitorRect.get_x(), lMonitorRect.get_y()); + editWnd->maximize(); + editWnd->show(); + } else { + editWnd->show_all(); + } + } + + return editWnd; +} + +EditWindow::EditWindow (RTWindow* p) : parent(p) , isFullscreen(false) { + + Glib::ustring fName = "rt-logo.png"; + Glib::ustring fullPath = RTImage::findIconAbsolutePath(fName); + +#ifdef GLIBMM_EXCEPTIONS_ENABLED + try { set_default_icon_from_file (fullPath); + } catch(Glib::Exception& ex) { printf ("%s\n", ex.what().c_str()); } +#else + { std::auto_ptr error; + set_default_icon_from_file (fullPath, error); + } +#endif //GLIBMM_EXCEPTIONS_ENABLED + set_title_decorated(""); + property_allow_shrink() = true; + set_modal(false); + set_resizable(true); + + property_destroy_with_parent().set_value(false); + signal_window_state_event().connect( sigc::mem_fun(*this, &EditWindow::on_window_state_event) ); + + mainNB = Gtk::manage (new Gtk::Notebook ()); + mainNB->set_scrollable (true); + mainNB->signal_switch_page().connect_notify( sigc::mem_fun(*this, &EditWindow::on_mainNB_switch_page) ); + + signal_key_press_event().connect( sigc::mem_fun(*this, &EditWindow::keyPressed) ); + + Gtk::VBox* mainBox = Gtk::manage (new Gtk::VBox ()); + mainBox->pack_start (*mainNB); + + add (*mainBox); + show_all (); +} + +void EditWindow::on_realize () { + Gtk::Window::on_realize (); + + cursorManager.init (get_window()); +} + +bool EditWindow::on_window_state_event(GdkEventWindowState* event) { + if (!event->new_window_state) { + // Window mode + options.windowMaximized = false; + } + else if (event->new_window_state & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN)) { + // Fullscreen mode + options.windowMaximized = true; + } + return true; +} + +void EditWindow::on_mainNB_switch_page(GtkNotebookPage* page, guint page_num) { + //if (page_num > 1) { + EditorPanel *ep = static_cast(mainNB->get_nth_page(page_num)); + + if (mainNB->get_n_pages()>1 && page_num<=(filesEdited.size()-1)){ + set_title_decorated(ep->getFileName()); + } + ep->setAspect(); + //} +} + +void EditWindow::addEditorPanel (EditorPanel* ep, const std::string &name) { + ep->setParent (parent); + + // construct closeable tab for the image + Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ()); + hb->pack_start (*Gtk::manage (new RTImage ("rtwindow.png"))); + hb->pack_start (*Gtk::manage (new Gtk::Label (Glib::path_get_basename (name)))); + hb->set_tooltip_markup (name); + Gtk::Button* closeb = Gtk::manage (new Gtk::Button ()); + closeb->set_image (*Gtk::manage(new RTImage ("gtk-close.png"))); + closeb->set_relief (Gtk::RELIEF_NONE); + closeb->set_focus_on_click (false); + // make the button as small as possible + Glib::RefPtr style = Gtk::RcStyle::create (); + style->set_xthickness (0); + style->set_ythickness (0); + + closeb->modify_style (style); + closeb->signal_clicked().connect( sigc::bind (sigc::mem_fun(*this, &EditWindow::remEditorPanel) , ep)); + hb->pack_end (*closeb); + hb->set_spacing (2); + hb->show_all (); + + mainNB->append_page (*ep, *hb); + mainNB->set_current_page (mainNB->page_num (*ep)); + mainNB->set_tab_reorderable (*ep, true); + + set_title_decorated(name); + + epanels[ name ] = ep; + filesEdited.insert ( name ); + parent->fpanel->refreshEditedState (filesEdited); + ep->setAspect(); +} + void EditWindow::remEditorPanel (EditorPanel* ep) { if (ep->getIsProcessing()) return; // Will crash if destroyed while loading - - epanels.erase (ep->getFileName()); - filesEdited.erase (ep->getFileName ()); - parent->fpanel->refreshEditedState (filesEdited); - - mainNB->remove_page (*ep); - if (mainNB->get_n_pages()>0){ - EditorPanel* ep1 = static_cast(mainNB->get_nth_page (mainNB->get_current_page())); - set_title_decorated(ep1->getFileName()); - } - else set_title_decorated(""); - // TODO: save options if wanted -} - -bool EditWindow::selectEditorPanel(const std::string &name) { - std::map::iterator iep = epanels.find(name); - - if (iep!=epanels.end()) { - mainNB->set_current_page (mainNB->page_num (*iep->second)); - set_title_decorated(name); - return true; - } - return false; -} - -bool EditWindow::keyPressed (GdkEventKey* event) { - bool ctrl = event->state & GDK_CONTROL_MASK; - - if(event->keyval == GDK_F11) { - toggleFullscreen(); - return true; - } - else { - if(mainNB->get_n_pages ()>0) { //pass the handling for the editor panels, if there are any - if (event->keyval == GDK_w && ctrl){ //remove editor panel - EditorPanel* ep = static_cast(mainNB->get_nth_page (mainNB->get_current_page())); - remEditorPanel (ep); - return true; - } - else if(mainNB->get_n_pages ()>0){ - EditorPanel* ep = static_cast(mainNB->get_nth_page (mainNB->get_current_page())); - return ep->handleShortcutKey (event); - } - } - return false; - } - -} - -void EditWindow::toggleFullscreen () { - isFullscreen ? unfullscreen() : fullscreen(); - isFullscreen = !isFullscreen; -} - -bool EditWindow::on_delete_event(GdkEventAny* event) { - // Check if any editor is still processing, and do NOT quit if so. Otherwise crashes and inconsistent caches - bool isProcessing=false; - - for ( std::set ::iterator iter = filesEdited.begin(); iter != filesEdited.end() && !isProcessing; iter++ ) { - if (epanels[*iter]->getIsProcessing()) isProcessing=true; - } - + + epanels.erase (ep->getFileName()); + filesEdited.erase (ep->getFileName ()); + parent->fpanel->refreshEditedState (filesEdited); + + mainNB->remove_page (*ep); + if (mainNB->get_n_pages()>0){ + EditorPanel* ep1 = static_cast(mainNB->get_nth_page (mainNB->get_current_page())); + set_title_decorated(ep1->getFileName()); + } + else set_title_decorated(""); + // TODO: save options if wanted +} + +bool EditWindow::selectEditorPanel(const std::string &name) { + std::map::iterator iep = epanels.find(name); + + if (iep!=epanels.end()) { + mainNB->set_current_page (mainNB->page_num (*iep->second)); + set_title_decorated(name); + return true; + } + return false; +} + +bool EditWindow::keyPressed (GdkEventKey* event) { + bool ctrl = event->state & GDK_CONTROL_MASK; + + if(event->keyval == GDK_F11) { + toggleFullscreen(); + return true; + } + else { + if(mainNB->get_n_pages ()>0) { //pass the handling for the editor panels, if there are any + if (event->keyval == GDK_w && ctrl){ //remove editor panel + EditorPanel* ep = static_cast(mainNB->get_nth_page (mainNB->get_current_page())); + remEditorPanel (ep); + return true; + } + else if(mainNB->get_n_pages ()>0){ + EditorPanel* ep = static_cast(mainNB->get_nth_page (mainNB->get_current_page())); + return ep->handleShortcutKey (event); + } + } + return false; + } + +} + +void EditWindow::toggleFullscreen () { + isFullscreen ? unfullscreen() : fullscreen(); + isFullscreen = !isFullscreen; +} + +bool EditWindow::on_delete_event(GdkEventAny* event) { + // Check if any editor is still processing, and do NOT quit if so. Otherwise crashes and inconsistent caches + bool isProcessing=false; + + for ( std::set ::iterator iter = filesEdited.begin(); iter != filesEdited.end() && !isProcessing; iter++ ) { + if (epanels[*iter]->getIsProcessing()) isProcessing=true; + } + if (isProcessing) - return true; - - for ( std::set ::iterator iter = filesEdited.begin(); iter != filesEdited.end(); iter++ ) - mainNB->remove_page (*epanels[*iter]); - - epanels.clear(); - - filesEdited.clear(); - parent->fpanel->refreshEditedState (filesEdited); - - hide (); - return false; -} - -void EditWindow::set_title_decorated(Glib::ustring fname){ - Glib::ustring subtitle; - if (!fname.empty()) subtitle= " - " + fname; - set_title("RawTherapee "+ M("EDITWINDOW_TITLE") + subtitle); -} + return true; + + for ( std::set ::iterator iter = filesEdited.begin(); iter != filesEdited.end(); iter++ ) + mainNB->remove_page (*epanels[*iter]); + + epanels.clear(); + + filesEdited.clear(); + parent->fpanel->refreshEditedState (filesEdited); + + hide (); + return false; +} + +void EditWindow::set_title_decorated(Glib::ustring fname){ + Glib::ustring subtitle; + if (!fname.empty()) subtitle= " - " + fname; + set_title("RawTherapee "+ M("EDITWINDOW_TITLE") + subtitle); +} diff --git a/rtgui/exportpanel.cc b/rtgui/exportpanel.cc index 7c116b73e..28e80e1c4 100644 --- a/rtgui/exportpanel.cc +++ b/rtgui/exportpanel.cc @@ -1,422 +1,422 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * Copyright (c) 2012 Michael Ezra - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "exportpanel.h" -#include "multilangmgr.h" -#include "options.h" -#include "rtimage.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -ExportPanel::ExportPanel () : listener (NULL) { - - set_border_width (4); - - /*enabled = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_ENABLE")) ); - pack_start(*enabled, Gtk::PACK_SHRINK, 4); - pack_start (*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 2);*/ - - Gtk::Label* labExportTitle = Gtk::manage ( new Gtk::Label (M("EXPORT_FASTEXPORTOPTIONS")) ); - labExportTitle->set_use_markup (true); - labExportTitle->set_tooltip_text (M("EXPORT_INSTRUCTIONS")); - labExportTitle->set_alignment(Gtk::ALIGN_LEFT); - pack_start(*labExportTitle, Gtk::PACK_SHRINK, 4); - - bypass_ALL = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_ALL"))); - bypass_sharpening = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENING"))); - bypass_sharpenEdge = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENEDGE"))); - bypass_sharpenMicro = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENMICRO"))); - //bypass_lumaDenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_LUMADENOISE"))); - //bypass_colorDenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_COLORDENOISE"))); - bypass_defringe = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DEFRINGE"))); - bypass_dirpyrDenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DIRPYRDENOISE"))); - bypass_sh_hq = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SH_HQ"))); - bypass_dirpyrequalizer = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DIRPYREQUALIZER"))); - bypass_wavelet = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_EQUALIZER"))); - bypass_raw_ccSteps = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_CCSTEPS"))); - bypass_raw_ca = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_CA"))); - bypass_raw_df = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_DF"))); - bypass_raw_ff = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_FF"))); - - // ---------------------- Bayer sensor frame ----------------------- - - Gtk::Frame *bayerFrame = Gtk::manage( new Gtk::Frame(M("TP_RAW_SENSOR_BAYER"))); - Gtk::VBox* bayerFrameVBox = Gtk::manage (new Gtk::VBox ()); - - Gtk::HBox* hb_raw_bayer_method = Gtk::manage (new Gtk::HBox ()); - hb_raw_bayer_method->pack_start (*Gtk::manage (new Gtk::Label ( M("EXPORT_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4); - raw_bayer_method = Gtk::manage (new MyComboBoxText ()); - for( size_t i=0; i< procparams::RAWParams::BayerSensor::numMethods;i++) - raw_bayer_method->append_text(procparams::RAWParams::BayerSensor::methodstring[i]); - - raw_bayer_method->set_active(0); - hb_raw_bayer_method->pack_end (*raw_bayer_method, Gtk::PACK_EXPAND_WIDGET, 4); - - //bypass_raw_all_enhance = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_ALL_ENHANCE"))); - bypass_raw_bayer_linenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_LINENOISE"))); - bypass_raw_bayer_greenthresh = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_GREENTHRESH"))); - bypass_raw_bayer_dcb_iterations = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_DCB_ITERATIONS"))); - bypass_raw_bayer_dcb_enhance = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_DCB_ENHANCE"))); - bypass_raw_bayer_lmmse_iterations = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_LMMSE_ITERATIONS"))); - - // ---------------------- Bayer sensor frame ----------------------- - - Gtk::Frame *xtransFrame = Gtk::manage( new Gtk::Frame(M("TP_RAW_SENSOR_XTRANS"))); - Gtk::VBox* xtransFrameVBox = Gtk::manage (new Gtk::VBox ()); - - Gtk::HBox* hb_raw_xtrans_method = Gtk::manage (new Gtk::HBox ()); - hb_raw_xtrans_method->pack_start (*Gtk::manage (new Gtk::Label ( M("EXPORT_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4); - raw_xtrans_method = Gtk::manage (new MyComboBoxText ()); - for( size_t i=0; i< procparams::RAWParams::XTransSensor::numMethods;i++) - raw_xtrans_method->append_text(procparams::RAWParams::XTransSensor::methodstring[i]); - - raw_xtrans_method->set_active(0); - hb_raw_xtrans_method->pack_end (*raw_xtrans_method, Gtk::PACK_EXPAND_WIDGET, 4); - - // ---------------------------------------------------------------- - - // start global packing - pack_start(*bypass_ALL , Gtk::PACK_SHRINK, 4); - pack_start(*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 4); - pack_start(*bypass_sharpening , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_sharpenEdge , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_sharpenMicro , Gtk::PACK_SHRINK, 4); - //pack_start(*bypass_lumaDenoise , Gtk::PACK_SHRINK, 4); - //pack_start(*bypass_colorDenoise , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_defringe , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_dirpyrDenoise, Gtk::PACK_SHRINK, 4); - pack_start(*bypass_sh_hq , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_dirpyrequalizer , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_wavelet , Gtk::PACK_SHRINK, 4); - - bayerFrameVBox->pack_start(*hb_raw_bayer_method, Gtk::PACK_SHRINK, 4); - //bayerFrameVBox->pack_start(*bypass_raw_all_enhance , Gtk::PACK_SHRINK, 4); - bayerFrameVBox->pack_start(*bypass_raw_bayer_dcb_iterations, Gtk::PACK_SHRINK, 4); - bayerFrameVBox->pack_start(*bypass_raw_bayer_dcb_enhance , Gtk::PACK_SHRINK, 4); - bayerFrameVBox->pack_start(*bypass_raw_bayer_lmmse_iterations, Gtk::PACK_SHRINK, 4); - bayerFrameVBox->pack_start(*bypass_raw_bayer_linenoise , Gtk::PACK_SHRINK, 4); - bayerFrameVBox->pack_start(*bypass_raw_bayer_greenthresh , Gtk::PACK_SHRINK, 4); - bayerFrame->add(*bayerFrameVBox); - - xtransFrameVBox->pack_start(*hb_raw_xtrans_method, Gtk::PACK_SHRINK, 4); - xtransFrame->add(*xtransFrameVBox); - - pack_start(*bypass_raw_ccSteps , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_raw_ca , Gtk::PACK_SHRINK, 4); - - pack_start(*bypass_raw_df , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_raw_ff , Gtk::PACK_SHRINK, 4); - - pack_start (*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 2); - - // Resize options - - Gtk::HBox* rmbox = Gtk::manage (new Gtk::HBox ()); - rmbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_LABEL"))), Gtk::PACK_SHRINK, 4); - pack_start (*rmbox, Gtk::PACK_SHRINK, 4); - - Gtk::HBox* wbox = Gtk::manage (new Gtk::HBox ()); - Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox ()); - MaxWidth = Gtk::manage (new MySpinButton ()); - MaxHeight = Gtk::manage (new MySpinButton ()); - wbox->pack_start (*Gtk::manage (new Gtk::Label (M("EXPORT_MAXWIDTH"))), Gtk::PACK_SHRINK, 4); - wbox->pack_start (*MaxWidth); - hbox->pack_start (*Gtk::manage (new Gtk::Label (M("EXPORT_MAXHEIGHT"))), Gtk::PACK_SHRINK, 4); - hbox->pack_start (*MaxHeight); - pack_start (*wbox, Gtk::PACK_SHRINK, 4); - pack_start (*hbox, Gtk::PACK_SHRINK, 4); - - MaxWidth->set_digits (0); - MaxWidth->set_increments (1,100); - MaxWidth->set_value (options.fastexport_resize_width); - MaxWidth->set_range (32, 3000); - - MaxHeight->set_digits (0); - MaxHeight->set_increments (1,100); - MaxHeight->set_value (options.fastexport_resize_height); - MaxHeight->set_range (32, 3000); - - // Buttons - btnFastExport = Gtk::manage ( new Gtk::Button (M("EXPORT_PUTTOQUEUEFAST")) ); - btnFastExport->set_image (*Gtk::manage (new RTImage ("processing.png"))); - pack_start(*btnFastExport, Gtk::PACK_SHRINK, 4); - - - // add panel ending - Gtk::VBox* vboxpe = Gtk::manage (new Gtk::VBox ()); - Gtk::HSeparator* hseptpe = Gtk::manage (new Gtk::HSeparator ()); - Gtk::Image* peImg = Gtk::manage (new RTImage("PanelEnding.png")); - vboxpe->pack_start(*hseptpe, Gtk::PACK_SHRINK, 4); - vboxpe->pack_start(*peImg); - pack_start(*vboxpe, Gtk::PACK_SHRINK, 0); - - - btnFastExport->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::FastExportPressed) ); - //btnExportLoadSettings->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::LoadSettings) ); - //btnExportSaveSettings->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::SaveSettings) ); - bypass_ALLconn = bypass_ALL->signal_toggled().connect (sigc::mem_fun(*this, &ExportPanel::bypassALL_Toggled)); - - bypass_sharpeningConn = bypass_sharpening->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_sharpenEdgeConn = bypass_sharpenEdge->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_sharpenMicroConn = bypass_sharpenMicro->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - //bypass_lumaDenoiseConn = bypass_lumaDenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - //bypass_colorDenoiseConn = bypass_colorDenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_defringeConn = bypass_defringe->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_dirpyrDenoiseConn = bypass_dirpyrDenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_sh_hqConn = bypass_sh_hq->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_dirpyrequalizerConn = bypass_dirpyrequalizer->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_waveletConn = bypass_wavelet->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - //bypass_raw_all_enhanceConn = bypass_raw_bayer_all_enhance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_raw_bayer_dcb_iterationsConn = bypass_raw_bayer_dcb_iterations->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_raw_bayer_dcb_enhanceConn = bypass_raw_bayer_dcb_enhance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_raw_bayer_lmmse_iterationsConn = bypass_raw_bayer_lmmse_iterations->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_raw_bayer_linenoiseConn = bypass_raw_bayer_linenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_raw_bayer_greenthreshConn = bypass_raw_bayer_greenthresh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_raw_ccStepsConn = bypass_raw_ccSteps->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_raw_caConn = bypass_raw_ca->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_raw_dfConn = bypass_raw_df->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - bypass_raw_ffConn = bypass_raw_ff->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); - - LoadDefaultSettings(); -} - -/*bool ExportPanel::isEnabled () { - - return enabled->get_active () && is_sensitive(); -}*/ - - -void ExportPanel::FastExportPressed (){ - // options is the container for making these settings available globally. - // Therefore, settings must be saved to options before they are used further - SaveSettingsAsDefault(); - - if (listener) - listener->exportRequested (); -} - -void ExportPanel::SaveSettingsAsDefault(){ - // Save fast export settings to options - options.fastexport_bypass_sharpening = bypass_sharpening->get_active (); - options.fastexport_bypass_sharpenEdge = bypass_sharpenEdge->get_active (); - options.fastexport_bypass_sharpenMicro = bypass_sharpenMicro->get_active (); - //options.fastexport_bypass_lumaDenoise = bypass_lumaDenoise->get_active (); - //options.fastexport_bypass_colorDenoise = bypass_colorDenoise->get_active (); - options.fastexport_bypass_defringe = bypass_defringe->get_active (); - options.fastexport_bypass_dirpyrDenoise = bypass_dirpyrDenoise->get_active (); - options.fastexport_bypass_sh_hq = bypass_sh_hq->get_active (); - options.fastexport_bypass_dirpyrequalizer = bypass_dirpyrequalizer->get_active (); - options.fastexport_bypass_wavelet = bypass_wavelet->get_active (); - //options.fastexport_bypass_raw_bayer_all_enhance = bypass_raw_all_enhance->get_active (); - options.fastexport_bypass_raw_bayer_dcb_iterations = bypass_raw_bayer_dcb_iterations->get_active (); - options.fastexport_bypass_raw_bayer_dcb_enhance = bypass_raw_bayer_dcb_enhance->get_active (); - options.fastexport_bypass_raw_bayer_lmmse_iterations = bypass_raw_bayer_lmmse_iterations->get_active(); - options.fastexport_bypass_raw_bayer_linenoise = bypass_raw_bayer_linenoise->get_active (); - options.fastexport_bypass_raw_bayer_greenthresh = bypass_raw_bayer_greenthresh->get_active (); - options.fastexport_bypass_raw_ccSteps = bypass_raw_ccSteps->get_active (); - options.fastexport_bypass_raw_ca = bypass_raw_ca->get_active (); - options.fastexport_bypass_raw_df = bypass_raw_df->get_active (); - options.fastexport_bypass_raw_ff = bypass_raw_ff->get_active (); - - //saving Bayer demosaic_method - int currentRow = raw_bayer_method->get_active_row_number(); - if( currentRow>=0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) - options.fastexport_raw_bayer_method = procparams::RAWParams::BayerSensor::methodstring[currentRow]; - - //saving X-Trans demosaic_method - currentRow = raw_xtrans_method->get_active_row_number(); - if( currentRow>=0 && currentRow < procparams::RAWParams::XTransSensor::numMethods) - options.fastexport_raw_xtrans_method = procparams::RAWParams::XTransSensor::methodstring[currentRow]; - -// options.fastexport_icm_input = icm_input ; -// options.fastexport_icm_working = icm_working ; -// options.fastexport_icm_output = icm_output ; -// options.fastexport_icm_gamma = icm_gamma ; -// options.fastexport_resize_enabled = resize_enabled ; -// options.fastexport_resize_scale = resize_scale ; -// options.fastexport_resize_appliesTo = resize_appliesTo; -// options.fastexport_resize_dataspec = resize_dataspec ; - - options.fastexport_resize_method = "Lanczos"; - options.fastexport_resize_width = MaxWidth->get_value_as_int (); - options.fastexport_resize_height = MaxHeight->get_value_as_int (); -} - -void ExportPanel::LoadDefaultSettings(){ - // Load fast export settings from options - bypass_sharpening->set_active (options.fastexport_bypass_sharpening ); - bypass_sharpenEdge->set_active (options.fastexport_bypass_sharpenEdge ); - bypass_sharpenMicro->set_active (options.fastexport_bypass_sharpenMicro ); - //bypass_lumaDenoise->set_active (options.fastexport_bypass_lumaDenoise ); - //bypass_colorDenoise->set_active (options.fastexport_bypass_colorDenoise ); - bypass_defringe->set_active (options.fastexport_bypass_defringe ); - bypass_dirpyrDenoise->set_active (options.fastexport_bypass_dirpyrDenoise ); - bypass_sh_hq->set_active (options.fastexport_bypass_sh_hq ); - bypass_dirpyrequalizer->set_active (options.fastexport_bypass_dirpyrequalizer ); - bypass_wavelet->set_active (options.fastexport_bypass_wavelet ); - //bypass_raw_bayer_all_enhance->set_active (options.fastexport_bypass_raw_bayer_all_enhance ); - bypass_raw_bayer_dcb_iterations->set_active (options.fastexport_bypass_raw_bayer_dcb_iterations ); - bypass_raw_bayer_dcb_enhance->set_active (options.fastexport_bypass_raw_bayer_dcb_enhance ); - bypass_raw_bayer_lmmse_iterations->set_active(options.fastexport_bypass_raw_bayer_lmmse_iterations); - bypass_raw_bayer_linenoise->set_active (options.fastexport_bypass_raw_bayer_linenoise ); - bypass_raw_bayer_greenthresh->set_active (options.fastexport_bypass_raw_bayer_greenthresh ); - bypass_raw_ccSteps->set_active (options.fastexport_bypass_raw_ccSteps ); - bypass_raw_ca->set_active (options.fastexport_bypass_raw_ca ); - bypass_raw_df->set_active (options.fastexport_bypass_raw_df ); - bypass_raw_ff->set_active (options.fastexport_bypass_raw_ff ); - - // Bayer demosaic method - raw_bayer_method->set_active(procparams::RAWParams::BayerSensor::numMethods); - for( size_t i=0; i< procparams::RAWParams::BayerSensor::numMethods;i++) - if( options.fastexport_raw_bayer_method == procparams::RAWParams::BayerSensor::methodstring[i]) { - raw_bayer_method->set_active(i); - break; - } - - // X-Trans demosaic method - raw_xtrans_method->set_active(procparams::RAWParams::XTransSensor::numMethods); - for( size_t i=0; i< procparams::RAWParams::XTransSensor::numMethods;i++) - if( options.fastexport_raw_xtrans_method == procparams::RAWParams::XTransSensor::methodstring[i]) { - raw_xtrans_method->set_active(i); - break; - } - -// icm_input = options.fastexport_icm_input ; -// icm_working = options.fastexport_icm_working ; -// icm_output = options.fastexport_icm_output ; -// icm_gamma = options.fastexport_icm_gamma ; -// resize_enabled = options.fastexport_resize_enabled ; -// resize_scale = options.fastexport_resize_scale ; -// resize_appliesTo = options.fastexport_resize_appliesTo; -// resize_dataspec = options.fastexport_resize_dataspec ; - - MaxWidth->set_value(options.fastexport_resize_width); - MaxHeight->set_value(options.fastexport_resize_height); -} - -void ExportPanel::LoadSettings(){ - // load settings from file -} - -void ExportPanel::SaveSettings(){ - // save settings to file - -} - -void ExportPanel::bypassALL_Toggled(){ - bypass_sharpeningConn.block (true); - bypass_sharpenEdgeConn.block (true); - bypass_sharpenMicroConn.block (true); - //bypass_lumaDenoiseConn.block (true); - //bypass_colorDenoiseConn.block (true); - bypass_defringeConn.block (true); - bypass_dirpyrDenoiseConn.block (true); - bypass_sh_hqConn.block (true); - bypass_dirpyrequalizerConn.block (true); - bypass_waveletConn.block (true); - //bypass_raw_bayer_all_enhanceConn.block (true); - bypass_raw_bayer_dcb_iterationsConn.block (true); - bypass_raw_bayer_dcb_enhanceConn.block (true); - bypass_raw_bayer_lmmse_iterationsConn.block (true); - bypass_raw_bayer_linenoiseConn.block (true); - bypass_raw_bayer_greenthreshConn.block (true); - bypass_raw_ccStepsConn.block (true); - bypass_raw_caConn.block (true); - bypass_raw_dfConn.block (true); - bypass_raw_ffConn.block (true); - - bypass_ALL->set_inconsistent (false); - - bypass_sharpening->set_active(bypass_ALL->get_active()); - bypass_sharpenEdge->set_active(bypass_ALL->get_active()); - bypass_sharpenMicro->set_active(bypass_ALL->get_active()); - //bypass_lumaDenoise->set_active(bypass_ALL->get_active()); - //bypass_colorDenoise->set_active(bypass_ALL->get_active()); - bypass_defringe->set_active(bypass_ALL->get_active()); - bypass_dirpyrDenoise->set_active(bypass_ALL->get_active()); - bypass_sh_hq->set_active(bypass_ALL->get_active()); - bypass_dirpyrequalizer->set_active(bypass_ALL->get_active()); - bypass_wavelet->set_active(bypass_ALL->get_active()); - //bypass_raw_bayer_all_enhance->set_active(bypass_ALL->get_active()); - bypass_raw_bayer_dcb_iterations->set_active(bypass_ALL->get_active()); - bypass_raw_bayer_dcb_enhance->set_active(bypass_ALL->get_active()); - bypass_raw_bayer_lmmse_iterations->set_active(bypass_ALL->get_active()); - bypass_raw_bayer_linenoise->set_active(bypass_ALL->get_active()); - bypass_raw_bayer_greenthresh->set_active(bypass_ALL->get_active()); - bypass_raw_ccSteps->set_active(bypass_ALL->get_active()); - bypass_raw_ca->set_active(bypass_ALL->get_active()); - bypass_raw_df->set_active(bypass_ALL->get_active()); - bypass_raw_ff->set_active(bypass_ALL->get_active()); - - bypass_sharpeningConn.block (false); - bypass_sharpenEdgeConn.block (false); - bypass_sharpenMicroConn.block (false); - //bypass_lumaDenoiseConn.block (false); - //bypass_colorDenoiseConn.block (false); - bypass_defringeConn.block (false); - bypass_dirpyrDenoiseConn.block (false); - bypass_sh_hqConn.block (false); - bypass_dirpyrequalizerConn.block (false); - bypass_waveletConn.block (false); - //bypass_raw_bayer_all_enhanceConn.block (false); - bypass_raw_bayer_dcb_iterationsConn.block (false); - bypass_raw_bayer_dcb_enhanceConn.block (false); - bypass_raw_bayer_lmmse_iterationsConn.block (false); - bypass_raw_bayer_linenoiseConn.block (false); - bypass_raw_bayer_greenthreshConn.block (false); - bypass_raw_ccStepsConn.block (false); - bypass_raw_caConn.block (false); - bypass_raw_dfConn.block (false); - bypass_raw_ffConn.block (false); -} - -/* -fastexport_bypass_sharpening -fastexport_bypass_sharpenEdge -fastexport_bypass_sharpenMicro -fastexport_bypass_lumaDenoise -fastexport_bypass_colorDenoise -fastexport_bypass_defringe -fastexport_bypass_dirpyrDenoise -fastexport_bypass_sh_hq -fastexport_bypass_dirpyrequalizer -fastexport_raw_bayer_method -fastexport_bypass_raw_bayer_all_enhance -fastexport_bypass_raw_bayer_dcb_iterations -fastexport_bypass_raw_bayer_dcb_enhance -fastexport_bypass_raw_bayer_linenoise -fastexport_bypass_raw_bayer_greenthresh -fastexport_raw_xtrans_method -fastexport_bypass_raw_ccSteps -fastexport_bypass_raw_ca -fastexport_bypass_raw_df -fastexport_bypass_raw_ff -fastexport_icm_input -fastexport_icm_working -fastexport_icm_output -fastexport_icm_gamma -fastexport_resize_enabled -fastexport_resize_scale -fastexport_resize_appliesTo -fastexport_resize_method -fastexport_resize_dataspec -fastexport_resize_width -fastexport_resize_height -*/ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2012 Michael Ezra + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "exportpanel.h" +#include "multilangmgr.h" +#include "options.h" +#include "rtimage.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +ExportPanel::ExportPanel () : listener (NULL) { + + set_border_width (4); + + /*enabled = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_ENABLE")) ); + pack_start(*enabled, Gtk::PACK_SHRINK, 4); + pack_start (*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 2);*/ + + Gtk::Label* labExportTitle = Gtk::manage ( new Gtk::Label (M("EXPORT_FASTEXPORTOPTIONS")) ); + labExportTitle->set_use_markup (true); + labExportTitle->set_tooltip_text (M("EXPORT_INSTRUCTIONS")); + labExportTitle->set_alignment(Gtk::ALIGN_LEFT); + pack_start(*labExportTitle, Gtk::PACK_SHRINK, 4); + + bypass_ALL = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_ALL"))); + bypass_sharpening = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENING"))); + bypass_sharpenEdge = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENEDGE"))); + bypass_sharpenMicro = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENMICRO"))); + //bypass_lumaDenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_LUMADENOISE"))); + //bypass_colorDenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_COLORDENOISE"))); + bypass_defringe = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DEFRINGE"))); + bypass_dirpyrDenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DIRPYRDENOISE"))); + bypass_sh_hq = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SH_HQ"))); + bypass_dirpyrequalizer = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DIRPYREQUALIZER"))); + bypass_wavelet = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_EQUALIZER"))); + bypass_raw_ccSteps = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_CCSTEPS"))); + bypass_raw_ca = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_CA"))); + bypass_raw_df = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_DF"))); + bypass_raw_ff = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_FF"))); + + // ---------------------- Bayer sensor frame ----------------------- + + Gtk::Frame *bayerFrame = Gtk::manage( new Gtk::Frame(M("TP_RAW_SENSOR_BAYER"))); + Gtk::VBox* bayerFrameVBox = Gtk::manage (new Gtk::VBox ()); + + Gtk::HBox* hb_raw_bayer_method = Gtk::manage (new Gtk::HBox ()); + hb_raw_bayer_method->pack_start (*Gtk::manage (new Gtk::Label ( M("EXPORT_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4); + raw_bayer_method = Gtk::manage (new MyComboBoxText ()); + for( size_t i=0; i< procparams::RAWParams::BayerSensor::numMethods;i++) + raw_bayer_method->append_text(procparams::RAWParams::BayerSensor::methodstring[i]); + + raw_bayer_method->set_active(0); + hb_raw_bayer_method->pack_end (*raw_bayer_method, Gtk::PACK_EXPAND_WIDGET, 4); + + //bypass_raw_all_enhance = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_ALL_ENHANCE"))); + bypass_raw_bayer_linenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_LINENOISE"))); + bypass_raw_bayer_greenthresh = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_GREENTHRESH"))); + bypass_raw_bayer_dcb_iterations = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_DCB_ITERATIONS"))); + bypass_raw_bayer_dcb_enhance = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_DCB_ENHANCE"))); + bypass_raw_bayer_lmmse_iterations = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_LMMSE_ITERATIONS"))); + + // ---------------------- Bayer sensor frame ----------------------- + + Gtk::Frame *xtransFrame = Gtk::manage( new Gtk::Frame(M("TP_RAW_SENSOR_XTRANS"))); + Gtk::VBox* xtransFrameVBox = Gtk::manage (new Gtk::VBox ()); + + Gtk::HBox* hb_raw_xtrans_method = Gtk::manage (new Gtk::HBox ()); + hb_raw_xtrans_method->pack_start (*Gtk::manage (new Gtk::Label ( M("EXPORT_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4); + raw_xtrans_method = Gtk::manage (new MyComboBoxText ()); + for( size_t i=0; i< procparams::RAWParams::XTransSensor::numMethods;i++) + raw_xtrans_method->append_text(procparams::RAWParams::XTransSensor::methodstring[i]); + + raw_xtrans_method->set_active(0); + hb_raw_xtrans_method->pack_end (*raw_xtrans_method, Gtk::PACK_EXPAND_WIDGET, 4); + + // ---------------------------------------------------------------- + + // start global packing + pack_start(*bypass_ALL , Gtk::PACK_SHRINK, 4); + pack_start(*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 4); + pack_start(*bypass_sharpening , Gtk::PACK_SHRINK, 4); + pack_start(*bypass_sharpenEdge , Gtk::PACK_SHRINK, 4); + pack_start(*bypass_sharpenMicro , Gtk::PACK_SHRINK, 4); + //pack_start(*bypass_lumaDenoise , Gtk::PACK_SHRINK, 4); + //pack_start(*bypass_colorDenoise , Gtk::PACK_SHRINK, 4); + pack_start(*bypass_defringe , Gtk::PACK_SHRINK, 4); + pack_start(*bypass_dirpyrDenoise, Gtk::PACK_SHRINK, 4); + pack_start(*bypass_sh_hq , Gtk::PACK_SHRINK, 4); + pack_start(*bypass_dirpyrequalizer , Gtk::PACK_SHRINK, 4); + pack_start(*bypass_wavelet , Gtk::PACK_SHRINK, 4); + + bayerFrameVBox->pack_start(*hb_raw_bayer_method, Gtk::PACK_SHRINK, 4); + //bayerFrameVBox->pack_start(*bypass_raw_all_enhance , Gtk::PACK_SHRINK, 4); + bayerFrameVBox->pack_start(*bypass_raw_bayer_dcb_iterations, Gtk::PACK_SHRINK, 4); + bayerFrameVBox->pack_start(*bypass_raw_bayer_dcb_enhance , Gtk::PACK_SHRINK, 4); + bayerFrameVBox->pack_start(*bypass_raw_bayer_lmmse_iterations, Gtk::PACK_SHRINK, 4); + bayerFrameVBox->pack_start(*bypass_raw_bayer_linenoise , Gtk::PACK_SHRINK, 4); + bayerFrameVBox->pack_start(*bypass_raw_bayer_greenthresh , Gtk::PACK_SHRINK, 4); + bayerFrame->add(*bayerFrameVBox); + + xtransFrameVBox->pack_start(*hb_raw_xtrans_method, Gtk::PACK_SHRINK, 4); + xtransFrame->add(*xtransFrameVBox); + + pack_start(*bypass_raw_ccSteps , Gtk::PACK_SHRINK, 4); + pack_start(*bypass_raw_ca , Gtk::PACK_SHRINK, 4); + + pack_start(*bypass_raw_df , Gtk::PACK_SHRINK, 4); + pack_start(*bypass_raw_ff , Gtk::PACK_SHRINK, 4); + + pack_start (*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 2); + + // Resize options + + Gtk::HBox* rmbox = Gtk::manage (new Gtk::HBox ()); + rmbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_LABEL"))), Gtk::PACK_SHRINK, 4); + pack_start (*rmbox, Gtk::PACK_SHRINK, 4); + + Gtk::HBox* wbox = Gtk::manage (new Gtk::HBox ()); + Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox ()); + MaxWidth = Gtk::manage (new MySpinButton ()); + MaxHeight = Gtk::manage (new MySpinButton ()); + wbox->pack_start (*Gtk::manage (new Gtk::Label (M("EXPORT_MAXWIDTH"))), Gtk::PACK_SHRINK, 4); + wbox->pack_start (*MaxWidth); + hbox->pack_start (*Gtk::manage (new Gtk::Label (M("EXPORT_MAXHEIGHT"))), Gtk::PACK_SHRINK, 4); + hbox->pack_start (*MaxHeight); + pack_start (*wbox, Gtk::PACK_SHRINK, 4); + pack_start (*hbox, Gtk::PACK_SHRINK, 4); + + MaxWidth->set_digits (0); + MaxWidth->set_increments (1,100); + MaxWidth->set_value (options.fastexport_resize_width); + MaxWidth->set_range (32, 3000); + + MaxHeight->set_digits (0); + MaxHeight->set_increments (1,100); + MaxHeight->set_value (options.fastexport_resize_height); + MaxHeight->set_range (32, 3000); + + // Buttons + btnFastExport = Gtk::manage ( new Gtk::Button (M("EXPORT_PUTTOQUEUEFAST")) ); + btnFastExport->set_image (*Gtk::manage (new RTImage ("processing.png"))); + pack_start(*btnFastExport, Gtk::PACK_SHRINK, 4); + + + // add panel ending + Gtk::VBox* vboxpe = Gtk::manage (new Gtk::VBox ()); + Gtk::HSeparator* hseptpe = Gtk::manage (new Gtk::HSeparator ()); + Gtk::Image* peImg = Gtk::manage (new RTImage("PanelEnding.png")); + vboxpe->pack_start(*hseptpe, Gtk::PACK_SHRINK, 4); + vboxpe->pack_start(*peImg); + pack_start(*vboxpe, Gtk::PACK_SHRINK, 0); + + + btnFastExport->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::FastExportPressed) ); + //btnExportLoadSettings->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::LoadSettings) ); + //btnExportSaveSettings->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::SaveSettings) ); + bypass_ALLconn = bypass_ALL->signal_toggled().connect (sigc::mem_fun(*this, &ExportPanel::bypassALL_Toggled)); + + bypass_sharpeningConn = bypass_sharpening->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_sharpenEdgeConn = bypass_sharpenEdge->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_sharpenMicroConn = bypass_sharpenMicro->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + //bypass_lumaDenoiseConn = bypass_lumaDenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + //bypass_colorDenoiseConn = bypass_colorDenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_defringeConn = bypass_defringe->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_dirpyrDenoiseConn = bypass_dirpyrDenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_sh_hqConn = bypass_sh_hq->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_dirpyrequalizerConn = bypass_dirpyrequalizer->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_waveletConn = bypass_wavelet->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + //bypass_raw_all_enhanceConn = bypass_raw_bayer_all_enhance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_raw_bayer_dcb_iterationsConn = bypass_raw_bayer_dcb_iterations->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_raw_bayer_dcb_enhanceConn = bypass_raw_bayer_dcb_enhance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_raw_bayer_lmmse_iterationsConn = bypass_raw_bayer_lmmse_iterations->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_raw_bayer_linenoiseConn = bypass_raw_bayer_linenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_raw_bayer_greenthreshConn = bypass_raw_bayer_greenthresh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_raw_ccStepsConn = bypass_raw_ccSteps->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_raw_caConn = bypass_raw_ca->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_raw_dfConn = bypass_raw_df->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_raw_ffConn = bypass_raw_ff->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + + LoadDefaultSettings(); +} + +/*bool ExportPanel::isEnabled () { + + return enabled->get_active () && is_sensitive(); +}*/ + + +void ExportPanel::FastExportPressed (){ + // options is the container for making these settings available globally. + // Therefore, settings must be saved to options before they are used further + SaveSettingsAsDefault(); + + if (listener) + listener->exportRequested (); +} + +void ExportPanel::SaveSettingsAsDefault(){ + // Save fast export settings to options + options.fastexport_bypass_sharpening = bypass_sharpening->get_active (); + options.fastexport_bypass_sharpenEdge = bypass_sharpenEdge->get_active (); + options.fastexport_bypass_sharpenMicro = bypass_sharpenMicro->get_active (); + //options.fastexport_bypass_lumaDenoise = bypass_lumaDenoise->get_active (); + //options.fastexport_bypass_colorDenoise = bypass_colorDenoise->get_active (); + options.fastexport_bypass_defringe = bypass_defringe->get_active (); + options.fastexport_bypass_dirpyrDenoise = bypass_dirpyrDenoise->get_active (); + options.fastexport_bypass_sh_hq = bypass_sh_hq->get_active (); + options.fastexport_bypass_dirpyrequalizer = bypass_dirpyrequalizer->get_active (); + options.fastexport_bypass_wavelet = bypass_wavelet->get_active (); + //options.fastexport_bypass_raw_bayer_all_enhance = bypass_raw_all_enhance->get_active (); + options.fastexport_bypass_raw_bayer_dcb_iterations = bypass_raw_bayer_dcb_iterations->get_active (); + options.fastexport_bypass_raw_bayer_dcb_enhance = bypass_raw_bayer_dcb_enhance->get_active (); + options.fastexport_bypass_raw_bayer_lmmse_iterations = bypass_raw_bayer_lmmse_iterations->get_active(); + options.fastexport_bypass_raw_bayer_linenoise = bypass_raw_bayer_linenoise->get_active (); + options.fastexport_bypass_raw_bayer_greenthresh = bypass_raw_bayer_greenthresh->get_active (); + options.fastexport_bypass_raw_ccSteps = bypass_raw_ccSteps->get_active (); + options.fastexport_bypass_raw_ca = bypass_raw_ca->get_active (); + options.fastexport_bypass_raw_df = bypass_raw_df->get_active (); + options.fastexport_bypass_raw_ff = bypass_raw_ff->get_active (); + + //saving Bayer demosaic_method + int currentRow = raw_bayer_method->get_active_row_number(); + if( currentRow>=0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) + options.fastexport_raw_bayer_method = procparams::RAWParams::BayerSensor::methodstring[currentRow]; + + //saving X-Trans demosaic_method + currentRow = raw_xtrans_method->get_active_row_number(); + if( currentRow>=0 && currentRow < procparams::RAWParams::XTransSensor::numMethods) + options.fastexport_raw_xtrans_method = procparams::RAWParams::XTransSensor::methodstring[currentRow]; + +// options.fastexport_icm_input = icm_input ; +// options.fastexport_icm_working = icm_working ; +// options.fastexport_icm_output = icm_output ; +// options.fastexport_icm_gamma = icm_gamma ; +// options.fastexport_resize_enabled = resize_enabled ; +// options.fastexport_resize_scale = resize_scale ; +// options.fastexport_resize_appliesTo = resize_appliesTo; +// options.fastexport_resize_dataspec = resize_dataspec ; + + options.fastexport_resize_method = "Lanczos"; + options.fastexport_resize_width = MaxWidth->get_value_as_int (); + options.fastexport_resize_height = MaxHeight->get_value_as_int (); +} + +void ExportPanel::LoadDefaultSettings(){ + // Load fast export settings from options + bypass_sharpening->set_active (options.fastexport_bypass_sharpening ); + bypass_sharpenEdge->set_active (options.fastexport_bypass_sharpenEdge ); + bypass_sharpenMicro->set_active (options.fastexport_bypass_sharpenMicro ); + //bypass_lumaDenoise->set_active (options.fastexport_bypass_lumaDenoise ); + //bypass_colorDenoise->set_active (options.fastexport_bypass_colorDenoise ); + bypass_defringe->set_active (options.fastexport_bypass_defringe ); + bypass_dirpyrDenoise->set_active (options.fastexport_bypass_dirpyrDenoise ); + bypass_sh_hq->set_active (options.fastexport_bypass_sh_hq ); + bypass_dirpyrequalizer->set_active (options.fastexport_bypass_dirpyrequalizer ); + bypass_wavelet->set_active (options.fastexport_bypass_wavelet ); + //bypass_raw_bayer_all_enhance->set_active (options.fastexport_bypass_raw_bayer_all_enhance ); + bypass_raw_bayer_dcb_iterations->set_active (options.fastexport_bypass_raw_bayer_dcb_iterations ); + bypass_raw_bayer_dcb_enhance->set_active (options.fastexport_bypass_raw_bayer_dcb_enhance ); + bypass_raw_bayer_lmmse_iterations->set_active(options.fastexport_bypass_raw_bayer_lmmse_iterations); + bypass_raw_bayer_linenoise->set_active (options.fastexport_bypass_raw_bayer_linenoise ); + bypass_raw_bayer_greenthresh->set_active (options.fastexport_bypass_raw_bayer_greenthresh ); + bypass_raw_ccSteps->set_active (options.fastexport_bypass_raw_ccSteps ); + bypass_raw_ca->set_active (options.fastexport_bypass_raw_ca ); + bypass_raw_df->set_active (options.fastexport_bypass_raw_df ); + bypass_raw_ff->set_active (options.fastexport_bypass_raw_ff ); + + // Bayer demosaic method + raw_bayer_method->set_active(procparams::RAWParams::BayerSensor::numMethods); + for( size_t i=0; i< procparams::RAWParams::BayerSensor::numMethods;i++) + if( options.fastexport_raw_bayer_method == procparams::RAWParams::BayerSensor::methodstring[i]) { + raw_bayer_method->set_active(i); + break; + } + + // X-Trans demosaic method + raw_xtrans_method->set_active(procparams::RAWParams::XTransSensor::numMethods); + for( size_t i=0; i< procparams::RAWParams::XTransSensor::numMethods;i++) + if( options.fastexport_raw_xtrans_method == procparams::RAWParams::XTransSensor::methodstring[i]) { + raw_xtrans_method->set_active(i); + break; + } + +// icm_input = options.fastexport_icm_input ; +// icm_working = options.fastexport_icm_working ; +// icm_output = options.fastexport_icm_output ; +// icm_gamma = options.fastexport_icm_gamma ; +// resize_enabled = options.fastexport_resize_enabled ; +// resize_scale = options.fastexport_resize_scale ; +// resize_appliesTo = options.fastexport_resize_appliesTo; +// resize_dataspec = options.fastexport_resize_dataspec ; + + MaxWidth->set_value(options.fastexport_resize_width); + MaxHeight->set_value(options.fastexport_resize_height); +} + +void ExportPanel::LoadSettings(){ + // load settings from file +} + +void ExportPanel::SaveSettings(){ + // save settings to file + +} + +void ExportPanel::bypassALL_Toggled(){ + bypass_sharpeningConn.block (true); + bypass_sharpenEdgeConn.block (true); + bypass_sharpenMicroConn.block (true); + //bypass_lumaDenoiseConn.block (true); + //bypass_colorDenoiseConn.block (true); + bypass_defringeConn.block (true); + bypass_dirpyrDenoiseConn.block (true); + bypass_sh_hqConn.block (true); + bypass_dirpyrequalizerConn.block (true); + bypass_waveletConn.block (true); + //bypass_raw_bayer_all_enhanceConn.block (true); + bypass_raw_bayer_dcb_iterationsConn.block (true); + bypass_raw_bayer_dcb_enhanceConn.block (true); + bypass_raw_bayer_lmmse_iterationsConn.block (true); + bypass_raw_bayer_linenoiseConn.block (true); + bypass_raw_bayer_greenthreshConn.block (true); + bypass_raw_ccStepsConn.block (true); + bypass_raw_caConn.block (true); + bypass_raw_dfConn.block (true); + bypass_raw_ffConn.block (true); + + bypass_ALL->set_inconsistent (false); + + bypass_sharpening->set_active(bypass_ALL->get_active()); + bypass_sharpenEdge->set_active(bypass_ALL->get_active()); + bypass_sharpenMicro->set_active(bypass_ALL->get_active()); + //bypass_lumaDenoise->set_active(bypass_ALL->get_active()); + //bypass_colorDenoise->set_active(bypass_ALL->get_active()); + bypass_defringe->set_active(bypass_ALL->get_active()); + bypass_dirpyrDenoise->set_active(bypass_ALL->get_active()); + bypass_sh_hq->set_active(bypass_ALL->get_active()); + bypass_dirpyrequalizer->set_active(bypass_ALL->get_active()); + bypass_wavelet->set_active(bypass_ALL->get_active()); + //bypass_raw_bayer_all_enhance->set_active(bypass_ALL->get_active()); + bypass_raw_bayer_dcb_iterations->set_active(bypass_ALL->get_active()); + bypass_raw_bayer_dcb_enhance->set_active(bypass_ALL->get_active()); + bypass_raw_bayer_lmmse_iterations->set_active(bypass_ALL->get_active()); + bypass_raw_bayer_linenoise->set_active(bypass_ALL->get_active()); + bypass_raw_bayer_greenthresh->set_active(bypass_ALL->get_active()); + bypass_raw_ccSteps->set_active(bypass_ALL->get_active()); + bypass_raw_ca->set_active(bypass_ALL->get_active()); + bypass_raw_df->set_active(bypass_ALL->get_active()); + bypass_raw_ff->set_active(bypass_ALL->get_active()); + + bypass_sharpeningConn.block (false); + bypass_sharpenEdgeConn.block (false); + bypass_sharpenMicroConn.block (false); + //bypass_lumaDenoiseConn.block (false); + //bypass_colorDenoiseConn.block (false); + bypass_defringeConn.block (false); + bypass_dirpyrDenoiseConn.block (false); + bypass_sh_hqConn.block (false); + bypass_dirpyrequalizerConn.block (false); + bypass_waveletConn.block (false); + //bypass_raw_bayer_all_enhanceConn.block (false); + bypass_raw_bayer_dcb_iterationsConn.block (false); + bypass_raw_bayer_dcb_enhanceConn.block (false); + bypass_raw_bayer_lmmse_iterationsConn.block (false); + bypass_raw_bayer_linenoiseConn.block (false); + bypass_raw_bayer_greenthreshConn.block (false); + bypass_raw_ccStepsConn.block (false); + bypass_raw_caConn.block (false); + bypass_raw_dfConn.block (false); + bypass_raw_ffConn.block (false); +} + +/* +fastexport_bypass_sharpening +fastexport_bypass_sharpenEdge +fastexport_bypass_sharpenMicro +fastexport_bypass_lumaDenoise +fastexport_bypass_colorDenoise +fastexport_bypass_defringe +fastexport_bypass_dirpyrDenoise +fastexport_bypass_sh_hq +fastexport_bypass_dirpyrequalizer +fastexport_raw_bayer_method +fastexport_bypass_raw_bayer_all_enhance +fastexport_bypass_raw_bayer_dcb_iterations +fastexport_bypass_raw_bayer_dcb_enhance +fastexport_bypass_raw_bayer_linenoise +fastexport_bypass_raw_bayer_greenthresh +fastexport_raw_xtrans_method +fastexport_bypass_raw_ccSteps +fastexport_bypass_raw_ca +fastexport_bypass_raw_df +fastexport_bypass_raw_ff +fastexport_icm_input +fastexport_icm_working +fastexport_icm_output +fastexport_icm_gamma +fastexport_resize_enabled +fastexport_resize_scale +fastexport_resize_appliesTo +fastexport_resize_method +fastexport_resize_dataspec +fastexport_resize_width +fastexport_resize_height +*/ diff --git a/rtgui/exportpanel.h b/rtgui/exportpanel.h index bcbd44ea5..bdcb8a4cb 100644 --- a/rtgui/exportpanel.h +++ b/rtgui/exportpanel.h @@ -1,120 +1,120 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2012 Gabor Horvath - * Copyright (c) 2012 Michael Ezra - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _EXPORTPANEL_ -#define _EXPORTPANEL_ - -#include -#include "guiutils.h" -#include "adjuster.h" - -class ExportPanelListener { - - public: - virtual void exportRequested () {} -}; - -class ExportPanel : public Gtk::VBox { - - protected: - - //Gtk::CheckButton* enabled; - Gtk::CheckButton* bypass_ALL; - Gtk::CheckButton* bypass_sharpenEdge; - Gtk::CheckButton* bypass_sharpenMicro; - Gtk::CheckButton* bypass_sharpening; - //Gtk::CheckButton* bypass_lumaDenoise; - //Gtk::CheckButton* bypass_colorDenoise; - Gtk::CheckButton* bypass_defringe; - Gtk::CheckButton* bypass_dirpyrDenoise; - Gtk::CheckButton* bypass_sh_hq; - -/* icm_input = "(camera)"; - icm_working = "sRGB"; - icm_output = "RT_sRGB"; - icm_gamma = "default"; -*/ - Gtk::CheckButton* bypass_dirpyrequalizer; // also could leave untouched but disable only small radius adjustments - //Gtk::CheckButton* bypass_raw_all_enhance; - Gtk::CheckButton* bypass_wavelet; // also could leave untouched but disable only small radius adjustments - - MyComboBoxText* raw_bayer_method; - - Gtk::CheckButton* bypass_raw_bayer_dcb_iterations; - Gtk::CheckButton* bypass_raw_bayer_dcb_enhance; - Gtk::CheckButton* bypass_raw_bayer_lmmse_iterations; - //Gtk::CheckButton* bypass_raw_bayer_all_enhance; - Gtk::CheckButton* bypass_raw_bayer_linenoise; - Gtk::CheckButton* bypass_raw_bayer_greenthresh; - - Gtk::CheckButton* bypass_raw_ccSteps; - Gtk::CheckButton* bypass_raw_ca; //wraps raw.cared, raw.cablue, raw.ca_autocorrect - Gtk::CheckButton* bypass_raw_df; //wraps raw.dark_frame, raw.df_AutoSelect - Gtk::CheckButton* bypass_raw_ff; //wraps raw.ff_file, raw.ff_AutoSelect - - MyComboBoxText* raw_xtrans_method; - - Gtk::Button* btnFastExport; - Gtk::Button* btnExportLoadSettings; - Gtk::Button* btnExportSaveSettings; - - MySpinButton* MaxWidth; - MySpinButton* MaxHeight; - - sigc::connection enabledconn, bypass_ALLconn, FastExportconn, ExportLoadSettingsconn, ExportSaveSettingsconn; - sigc::connection bypass_sharpeningConn ; - sigc::connection bypass_sharpenEdgeConn ; - sigc::connection bypass_sharpenMicroConn ; - //sigc::connection bypass_lumaDenoiseConn ; - //sigc::connection bypass_colorDenoiseConn ; - sigc::connection bypass_defringeConn ; - sigc::connection bypass_dirpyrDenoiseConn ; - sigc::connection bypass_sh_hqConn ; - sigc::connection bypass_dirpyrequalizerConn ; - sigc::connection bypass_waveletConn ; - //sigc::connection bypass_raw_bayer_all_enhanceConn ; - sigc::connection bypass_raw_bayer_dcb_iterationsConn ; - sigc::connection bypass_raw_bayer_dcb_enhanceConn ; - sigc::connection bypass_raw_bayer_lmmse_iterationsConn; - sigc::connection bypass_raw_bayer_linenoiseConn ; - sigc::connection bypass_raw_bayer_greenthreshConn ; - sigc::connection bypass_raw_ccStepsConn ; - sigc::connection bypass_raw_caConn ; - sigc::connection bypass_raw_dfConn ; - sigc::connection bypass_raw_ffConn ; - - - ExportPanelListener* listener; - - void bypassALL_Toggled(); - void SaveSettingsAsDefault(); - void LoadDefaultSettings(); - void LoadSettings(); - void SaveSettings(); - - public: - ExportPanel (); - - void FastExportPressed (); - //bool isEnabled (); - - void setExportPanelListener (ExportPanelListener* l) { listener = l; } -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2012 Gabor Horvath + * Copyright (c) 2012 Michael Ezra + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _EXPORTPANEL_ +#define _EXPORTPANEL_ + +#include +#include "guiutils.h" +#include "adjuster.h" + +class ExportPanelListener { + + public: + virtual void exportRequested () {} +}; + +class ExportPanel : public Gtk::VBox { + + protected: + + //Gtk::CheckButton* enabled; + Gtk::CheckButton* bypass_ALL; + Gtk::CheckButton* bypass_sharpenEdge; + Gtk::CheckButton* bypass_sharpenMicro; + Gtk::CheckButton* bypass_sharpening; + //Gtk::CheckButton* bypass_lumaDenoise; + //Gtk::CheckButton* bypass_colorDenoise; + Gtk::CheckButton* bypass_defringe; + Gtk::CheckButton* bypass_dirpyrDenoise; + Gtk::CheckButton* bypass_sh_hq; + +/* icm_input = "(camera)"; + icm_working = "sRGB"; + icm_output = "RT_sRGB"; + icm_gamma = "default"; +*/ + Gtk::CheckButton* bypass_dirpyrequalizer; // also could leave untouched but disable only small radius adjustments + //Gtk::CheckButton* bypass_raw_all_enhance; + Gtk::CheckButton* bypass_wavelet; // also could leave untouched but disable only small radius adjustments + + MyComboBoxText* raw_bayer_method; + + Gtk::CheckButton* bypass_raw_bayer_dcb_iterations; + Gtk::CheckButton* bypass_raw_bayer_dcb_enhance; + Gtk::CheckButton* bypass_raw_bayer_lmmse_iterations; + //Gtk::CheckButton* bypass_raw_bayer_all_enhance; + Gtk::CheckButton* bypass_raw_bayer_linenoise; + Gtk::CheckButton* bypass_raw_bayer_greenthresh; + + Gtk::CheckButton* bypass_raw_ccSteps; + Gtk::CheckButton* bypass_raw_ca; //wraps raw.cared, raw.cablue, raw.ca_autocorrect + Gtk::CheckButton* bypass_raw_df; //wraps raw.dark_frame, raw.df_AutoSelect + Gtk::CheckButton* bypass_raw_ff; //wraps raw.ff_file, raw.ff_AutoSelect + + MyComboBoxText* raw_xtrans_method; + + Gtk::Button* btnFastExport; + Gtk::Button* btnExportLoadSettings; + Gtk::Button* btnExportSaveSettings; + + MySpinButton* MaxWidth; + MySpinButton* MaxHeight; + + sigc::connection enabledconn, bypass_ALLconn, FastExportconn, ExportLoadSettingsconn, ExportSaveSettingsconn; + sigc::connection bypass_sharpeningConn ; + sigc::connection bypass_sharpenEdgeConn ; + sigc::connection bypass_sharpenMicroConn ; + //sigc::connection bypass_lumaDenoiseConn ; + //sigc::connection bypass_colorDenoiseConn ; + sigc::connection bypass_defringeConn ; + sigc::connection bypass_dirpyrDenoiseConn ; + sigc::connection bypass_sh_hqConn ; + sigc::connection bypass_dirpyrequalizerConn ; + sigc::connection bypass_waveletConn ; + //sigc::connection bypass_raw_bayer_all_enhanceConn ; + sigc::connection bypass_raw_bayer_dcb_iterationsConn ; + sigc::connection bypass_raw_bayer_dcb_enhanceConn ; + sigc::connection bypass_raw_bayer_lmmse_iterationsConn; + sigc::connection bypass_raw_bayer_linenoiseConn ; + sigc::connection bypass_raw_bayer_greenthreshConn ; + sigc::connection bypass_raw_ccStepsConn ; + sigc::connection bypass_raw_caConn ; + sigc::connection bypass_raw_dfConn ; + sigc::connection bypass_raw_ffConn ; + + + ExportPanelListener* listener; + + void bypassALL_Toggled(); + void SaveSettingsAsDefault(); + void LoadDefaultSettings(); + void LoadSettings(); + void SaveSettings(); + + public: + ExportPanel (); + + void FastExportPressed (); + //bool isEnabled (); + + void setExportPanelListener (ExportPanelListener* l) { listener = l; } +}; + +#endif diff --git a/rtgui/extprog.cc b/rtgui/extprog.cc index f399b0b0f..a20414ba4 100644 --- a/rtgui/extprog.cc +++ b/rtgui/extprog.cc @@ -1,174 +1,174 @@ -/* -* This file is part of RawTherapee. -* -* Copyright (c) 2012 Oliver Duis -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -*/ -#include - -#include "extprog.h" -#include "multilangmgr.h" -#include "../rtengine/safegtk.h" -#ifdef WIN32 -#include -// for GCC32 -#ifndef _WIN32_IE -#define _WIN32_IE 0x0600 -#endif -#include -#endif -using namespace std; - - -ExtProgAction::ExtProgAction() {} - -ExtProgAction::ExtProgAction(const ExtProgAction* other, int target) - : target(target), filePathEXE(other->filePathEXE), preparams(other->preparams), name(other->name) { } - -Glib::ustring ExtProgAction::GetFullName() { - return name+ " [" + M(Glib::ustring::compose("EXTPROGTARGET_%1", target)) + "]"; -} - -bool ExtProgAction::Execute(std::vector fileNames) { - if (fileNames.empty()) return false; - - // Check if they all exists (maybe not precessed yet) - for (int i=0;i0) cmdLine += " " + preparams; - - for (int i=0;i::iterator it=lActions.begin();it!=lActions.end();it++) delete *it; -} - -// Reads all profiles from the given profiles dir -void ExtProgStore::init () { - MyMutex::MyLock lock(mtx); - - lActions.clear(); - -#ifdef WIN32 - - SearchProg("Photoshop", "Adobe\\Adobe Photoshop CS%1 (64 Bit)\\Photoshop.exe", "Adobe\\Adobe Photoshop CS%1\\Photoshop.exe", 9, false, true); - SearchProg("Photomatix Pro", "PhotomatixPro%1\\PhotomatixPro.exe", "", 9, true, true); - SearchProg("Paint.NET", "Paint.NET\\PaintDotNet.exe", "", 0, false, true); - SearchProg("MS Image Composition Editor", "Microsoft Research\\Image Composite Editor\\ICE.exe", "", 0, false, true); - SearchProg("PTGui", "PTGui\\PTGui.exe", "", 0, false, true); - SearchProg("GeoSetter", "GeoSetter\\GeoSetter.exe", "", 0, true, true); - SearchProg("FastStone Image Viewer", "FastStone Image Viewer\\FSViewer.exe", "", 0, true, true); - SearchProg("FastPictureViewer", "FastPictureViewer\\FastPictureViewer.exe", "", 0, true, true); - - if (!SearchProg("Autopano Giga 3", "Kolor\\Autopano Giga 3.%1\\AutopanoGiga_x64.exe", "Kolor\\Autopano Giga 3.%1\\AutopanoGiga.exe", 15, true, true)){ - if ( !SearchProg("Autopano Pro 3", "Kolor\\Autopano Pro 3.%1\\AutopanoPro_x64.exe", "Kolor\\Autopano Pro 3.%1\\AutopanoPro.exe", 15, true, true)) { - if (!SearchProg("Autopano Giga 2", "Kolor\\Autopano Giga 2.%1\\AutopanoGiga_x64.exe", "Kolor\\Autopano Giga 2.%1\\AutopanoGiga.exe", 6, true, true)) - SearchProg("Autopano Pro 2", "Kolor\\Autopano Pro 2.%1\\AutopanoPro_x64.exe", "Kolor\\Autopano Pro 2.%1\\AutopanoPro.exe", 6, true, true); - } - } - - // DO NOT add obscure little tools here, only widely used programs with proper setup program to have a standard path -#endif - -} - -bool ExtProgStore::SearchProg(Glib::ustring name, Glib::ustring exePath, Glib::ustring exePath86, int maxVer, bool allowRaw, bool allowQueueProcess) { - bool found=false; - -#ifdef WIN32 - // get_user_special_dir crashes on some Windows configurations. - // so we use the safe native functions here - static Glib::ustring progFilesDir,progFilesDirx86; - - if (progFilesDir.empty()) { - WCHAR pathW[MAX_PATH]={0}; char pathA[MAX_PATH]; - - // First prio folder (64bit, otherwise 32bit) - if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_PROGRAM_FILES,false)) { - char pathA[MAX_PATH]; - WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); - progFilesDir=Glib::ustring(pathA); - } - - if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_PROGRAM_FILESX86,false)) { - WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); - progFilesDirx86=Glib::ustring(pathA); - } - } - - if (exePath86.empty()) exePath86=exePath; - - ExtProgAction *pAct=new ExtProgAction(); - pAct->name=name; - pAct->target= (allowRaw?1:2); - - if (maxVer>0) { - for (int verNo=maxVer;verNo>=0;verNo--) { - pAct->filePathEXE=progFilesDir+"\\"+Glib::ustring::compose(exePath,verNo); - if (safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) break; - - pAct->filePathEXE=progFilesDirx86+"\\"+Glib::ustring::compose(exePath86,verNo); - if (safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) break; - - pAct->filePathEXE=""; - } - } else { - pAct->filePathEXE=progFilesDir+"\\"+exePath; - if (!safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) { - - pAct->filePathEXE=progFilesDirx86+"\\"+exePath86; - if (!safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) pAct->filePathEXE=""; - } - } - - if (pAct->filePathEXE.length()>0){ - lActions.push_back(pAct); - - // Copy for second target - if (allowRaw && allowQueueProcess) lActions.push_back(new ExtProgAction(pAct,2)); - - found=true; - } else delete pAct; -#endif - - return found; -} +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2012 Oliver Duis +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ +#include + +#include "extprog.h" +#include "multilangmgr.h" +#include "../rtengine/safegtk.h" +#ifdef WIN32 +#include +// for GCC32 +#ifndef _WIN32_IE +#define _WIN32_IE 0x0600 +#endif +#include +#endif +using namespace std; + + +ExtProgAction::ExtProgAction() {} + +ExtProgAction::ExtProgAction(const ExtProgAction* other, int target) + : target(target), filePathEXE(other->filePathEXE), preparams(other->preparams), name(other->name) { } + +Glib::ustring ExtProgAction::GetFullName() { + return name+ " [" + M(Glib::ustring::compose("EXTPROGTARGET_%1", target)) + "]"; +} + +bool ExtProgAction::Execute(std::vector fileNames) { + if (fileNames.empty()) return false; + + // Check if they all exists (maybe not precessed yet) + for (int i=0;i0) cmdLine += " " + preparams; + + for (int i=0;i::iterator it=lActions.begin();it!=lActions.end();it++) delete *it; +} + +// Reads all profiles from the given profiles dir +void ExtProgStore::init () { + MyMutex::MyLock lock(mtx); + + lActions.clear(); + +#ifdef WIN32 + + SearchProg("Photoshop", "Adobe\\Adobe Photoshop CS%1 (64 Bit)\\Photoshop.exe", "Adobe\\Adobe Photoshop CS%1\\Photoshop.exe", 9, false, true); + SearchProg("Photomatix Pro", "PhotomatixPro%1\\PhotomatixPro.exe", "", 9, true, true); + SearchProg("Paint.NET", "Paint.NET\\PaintDotNet.exe", "", 0, false, true); + SearchProg("MS Image Composition Editor", "Microsoft Research\\Image Composite Editor\\ICE.exe", "", 0, false, true); + SearchProg("PTGui", "PTGui\\PTGui.exe", "", 0, false, true); + SearchProg("GeoSetter", "GeoSetter\\GeoSetter.exe", "", 0, true, true); + SearchProg("FastStone Image Viewer", "FastStone Image Viewer\\FSViewer.exe", "", 0, true, true); + SearchProg("FastPictureViewer", "FastPictureViewer\\FastPictureViewer.exe", "", 0, true, true); + + if (!SearchProg("Autopano Giga 3", "Kolor\\Autopano Giga 3.%1\\AutopanoGiga_x64.exe", "Kolor\\Autopano Giga 3.%1\\AutopanoGiga.exe", 15, true, true)){ + if ( !SearchProg("Autopano Pro 3", "Kolor\\Autopano Pro 3.%1\\AutopanoPro_x64.exe", "Kolor\\Autopano Pro 3.%1\\AutopanoPro.exe", 15, true, true)) { + if (!SearchProg("Autopano Giga 2", "Kolor\\Autopano Giga 2.%1\\AutopanoGiga_x64.exe", "Kolor\\Autopano Giga 2.%1\\AutopanoGiga.exe", 6, true, true)) + SearchProg("Autopano Pro 2", "Kolor\\Autopano Pro 2.%1\\AutopanoPro_x64.exe", "Kolor\\Autopano Pro 2.%1\\AutopanoPro.exe", 6, true, true); + } + } + + // DO NOT add obscure little tools here, only widely used programs with proper setup program to have a standard path +#endif + +} + +bool ExtProgStore::SearchProg(Glib::ustring name, Glib::ustring exePath, Glib::ustring exePath86, int maxVer, bool allowRaw, bool allowQueueProcess) { + bool found=false; + +#ifdef WIN32 + // get_user_special_dir crashes on some Windows configurations. + // so we use the safe native functions here + static Glib::ustring progFilesDir,progFilesDirx86; + + if (progFilesDir.empty()) { + WCHAR pathW[MAX_PATH]={0}; char pathA[MAX_PATH]; + + // First prio folder (64bit, otherwise 32bit) + if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_PROGRAM_FILES,false)) { + char pathA[MAX_PATH]; + WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); + progFilesDir=Glib::ustring(pathA); + } + + if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_PROGRAM_FILESX86,false)) { + WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); + progFilesDirx86=Glib::ustring(pathA); + } + } + + if (exePath86.empty()) exePath86=exePath; + + ExtProgAction *pAct=new ExtProgAction(); + pAct->name=name; + pAct->target= (allowRaw?1:2); + + if (maxVer>0) { + for (int verNo=maxVer;verNo>=0;verNo--) { + pAct->filePathEXE=progFilesDir+"\\"+Glib::ustring::compose(exePath,verNo); + if (safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) break; + + pAct->filePathEXE=progFilesDirx86+"\\"+Glib::ustring::compose(exePath86,verNo); + if (safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) break; + + pAct->filePathEXE=""; + } + } else { + pAct->filePathEXE=progFilesDir+"\\"+exePath; + if (!safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) { + + pAct->filePathEXE=progFilesDirx86+"\\"+exePath86; + if (!safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) pAct->filePathEXE=""; + } + } + + if (pAct->filePathEXE.length()>0){ + lActions.push_back(pAct); + + // Copy for second target + if (allowRaw && allowQueueProcess) lActions.push_back(new ExtProgAction(pAct,2)); + + found=true; + } else delete pAct; +#endif + + return found; +} diff --git a/rtgui/extprog.h b/rtgui/extprog.h index 6401cc09f..f2d528fc6 100644 --- a/rtgui/extprog.h +++ b/rtgui/extprog.h @@ -1,59 +1,59 @@ -/* -* This file is part of RawTherapee. -* -* Copyright (c) 2012 Oliver Duis -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -*/ - -#ifndef _EXTPROG_ -#define _EXTPROG_ - -#include -#include -#include "threadutils.h" - -class ExtProgAction { -public: - ExtProgAction(); - ExtProgAction(const ExtProgAction* other, int target); - - Glib::ustring filePathEXE; - Glib::ustring preparams; // after EXE and before file names - Glib::ustring name; // already localized if necessary - int target; // 1=RAW files, 2=batch converted files - - Glib::ustring GetFullName(); // e.g. "Photoshop (RAW)" - - virtual bool Execute(std::vector fileNames); -}; - -// Stores all external programs that could be called by the user -class ExtProgStore { - MyMutex mtx; // covers actions - - bool SearchProg(Glib::ustring name, Glib::ustring exePath, Glib::ustring exePath86, int maxVer, bool allowRaw, bool allowQueueProcess); - -public: - ~ExtProgStore(); - - void init(); // searches computer for installed standard programs - static ExtProgStore* getInstance(); - - std::list lActions; -}; - -#define extProgStore ExtProgStore::getInstance() - -#endif +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2012 Oliver Duis +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ + +#ifndef _EXTPROG_ +#define _EXTPROG_ + +#include +#include +#include "threadutils.h" + +class ExtProgAction { +public: + ExtProgAction(); + ExtProgAction(const ExtProgAction* other, int target); + + Glib::ustring filePathEXE; + Glib::ustring preparams; // after EXE and before file names + Glib::ustring name; // already localized if necessary + int target; // 1=RAW files, 2=batch converted files + + Glib::ustring GetFullName(); // e.g. "Photoshop (RAW)" + + virtual bool Execute(std::vector fileNames); +}; + +// Stores all external programs that could be called by the user +class ExtProgStore { + MyMutex mtx; // covers actions + + bool SearchProg(Glib::ustring name, Glib::ustring exePath, Glib::ustring exePath86, int maxVer, bool allowRaw, bool allowQueueProcess); + +public: + ~ExtProgStore(); + + void init(); // searches computer for installed standard programs + static ExtProgStore* getInstance(); + + std::list lActions; +}; + +#define extProgStore ExtProgStore::getInstance() + +#endif diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 188f14658..3ab622c58 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1,2100 +1,2100 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * Copyright (c) 2011 Michael Ezra - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include -#include -#include -#include "../rtengine/rt_math.h" - -#include "filecatalog.h" -#include "filepanel.h" -#include "options.h" -#include "cachemanager.h" -#include "multilangmgr.h" -#include "guiutils.h" -#include "renamedlg.h" -#include "thumbimageupdater.h" -#include "../rtengine/safegtk.h" -#include "batchqueue.h" -#include "rtimage.h" - -using namespace std; - -#define CHECKTIME 2000 - -FileCatalog::FileCatalog (CoarsePanel* cp, ToolBar* tb, FilePanel* filepanel) : - filepanel(filepanel), - selectedDirectoryId(1), - listener(NULL), - fslistener(NULL), - dirlistener(NULL), - hasValidCurrentEFS(false), - filterPanel(NULL), - previewsToLoad(0), - previewsLoaded(0), - coarsePanel(cp), - toolBar(tb) - { - - inTabMode=false; - - // construct and initialize thumbnail browsers - fileBrowser = Gtk::manage( new FileBrowser() ); - fileBrowser->setFileBrowserListener (this); - fileBrowser->setArrangement (ThumbBrowserBase::TB_Vertical); - fileBrowser->show (); - - set_size_request(0,250); - // construct trash panel with the extra "empty trash" button - trashButtonBox = Gtk::manage( new Gtk::VBox ); - Gtk::Button* emptyT = Gtk::manage( new Gtk::Button (M("FILEBROWSER_EMPTYTRASH"))); - emptyT->set_tooltip_markup (M("FILEBROWSER_EMPTYTRASHHINT")); - emptyT->set_image (*Gtk::manage(new RTImage ("trash.png"))); - emptyT->signal_pressed().connect (sigc::mem_fun(*this, &FileCatalog::emptyTrash)); - trashButtonBox->pack_start (*emptyT, Gtk::PACK_SHRINK, 4); - emptyT->show (); - trashButtonBox->show (); - - //initialize hbToolBar1 - hbToolBar1 = Gtk::manage(new Gtk::HBox ()); - - //setup BrowsePath - iRefreshWhite = new RTImage("refresh-white.png"); - iRefreshRed = new RTImage("refresh-red.png"); - - BrowsePath = Gtk::manage(new Gtk::Entry ()); - BrowsePath->set_width_chars (50); - BrowsePath->set_tooltip_markup (M("FILEBROWSER_BROWSEPATHHINT")); - Gtk::HBox* hbBrowsePath = Gtk::manage(new Gtk::HBox ()); - buttonBrowsePath = Gtk::manage(new Gtk::Button ()); - buttonBrowsePath->set_image (*iRefreshWhite); - buttonBrowsePath->set_tooltip_markup (M("FILEBROWSER_BROWSEPATHBUTTONHINT")); - buttonBrowsePath->set_relief (Gtk::RELIEF_NONE); - buttonBrowsePath->signal_clicked().connect( sigc::mem_fun(*this, &FileCatalog::buttonBrowsePathPressed) ); - hbBrowsePath->pack_start (*BrowsePath, Gtk::PACK_EXPAND_WIDGET,0); - hbBrowsePath->pack_start (*buttonBrowsePath,Gtk::PACK_SHRINK, 0); - hbToolBar1->pack_start (*hbBrowsePath, Gtk::PACK_EXPAND_WIDGET,0); - - BrowsePath->signal_activate().connect (sigc::mem_fun(*this, &FileCatalog::buttonBrowsePathPressed)); //respond to the Enter key - BrowsePath->signal_key_press_event().connect(sigc::mem_fun(*this, &FileCatalog::BrowsePath_key_pressed)); - - //setup Query - iQueryClear = new RTImage("gtk-close-small.png"); - Gtk::Label* labelQuery = Gtk::manage(new Gtk::Label(M("FILEBROWSER_QUERYLABEL"))); - Query = Gtk::manage(new Gtk::Entry ()); // cannot use Gtk::manage here as FileCatalog::getFilter will fail on Query->get_text() - Query->set_text(""); - Query->set_width_chars (20); // TODO !!! add this value to options? - Query->set_tooltip_markup (M("FILEBROWSER_QUERYHINT")); - Gtk::HBox* hbQuery = Gtk::manage(new Gtk::HBox ()); - buttonQueryClear = Gtk::manage(new Gtk::Button ()); - buttonQueryClear->set_image (*iQueryClear); - buttonQueryClear->set_tooltip_markup (M("FILEBROWSER_QUERYBUTTONHINT")); - buttonQueryClear->set_relief (Gtk::RELIEF_NONE); - buttonQueryClear->signal_clicked().connect( sigc::mem_fun(*this, &FileCatalog::buttonQueryClearPressed) ); - hbQuery->pack_start (*labelQuery,Gtk::PACK_SHRINK, 0); - hbQuery->pack_start (*Query,Gtk::PACK_SHRINK, 0); - hbQuery->pack_start (*buttonQueryClear,Gtk::PACK_SHRINK, 0); - hbToolBar1->pack_start (*hbQuery, Gtk::PACK_SHRINK,0); - - Query->signal_activate().connect (sigc::mem_fun(*this, &FileCatalog::executeQuery)); //respond to the Enter key - Query->signal_key_press_event().connect(sigc::mem_fun(*this, &FileCatalog::Query_key_pressed)); - - // if NOT a single row toolbar - if (!options.FileBrowserToolbarSingleRow) pack_start (*hbToolBar1, Gtk::PACK_SHRINK,0); - - // setup button bar - buttonBar = Gtk::manage( new Gtk::HBox () ); - pack_start (*buttonBar, Gtk::PACK_SHRINK); - - buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); - - tbLeftPanel_1 = new Gtk::ToggleButton (); - iLeftPanel_1_Show = new RTImage("panel-to-right.png"); - iLeftPanel_1_Hide = new RTImage("panel-to-left.png"); - - tbLeftPanel_1->set_relief(Gtk::RELIEF_NONE); - tbLeftPanel_1->set_active (true); - tbLeftPanel_1->set_tooltip_markup (M("MAIN_TOOLTIP_SHOWHIDELP1")); - tbLeftPanel_1->set_image (*iLeftPanel_1_Hide); - tbLeftPanel_1->signal_toggled().connect( sigc::mem_fun(*this, &FileCatalog::tbLeftPanel_1_toggled) ); - buttonBar->pack_start (*tbLeftPanel_1, Gtk::PACK_SHRINK); - - buttonBar->pack_start (*(new Gtk::VSeparator), Gtk::PACK_SHRINK); - - - iFilterClear = new RTImage ("filterclear.png"); - igFilterClear = new RTImage ("filter.png"); - bFilterClear = Gtk::manage(new Gtk::ToggleButton ()); - bFilterClear->set_active (true); - bFilterClear->set_image(*iFilterClear);// (*Gtk::manage(new RTImage ("filterclear.png"))); - bFilterClear->set_relief (Gtk::RELIEF_NONE); - bFilterClear->set_tooltip_markup (M("FILEBROWSER_SHOWDIRHINT")); - bFilterClear->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); - bCateg[0] = bFilterClear->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bFilterClear, true)); - buttonBar->pack_start (*bFilterClear, Gtk::PACK_SHRINK); - buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); - - fltrVbox1 = Gtk::manage (new Gtk::VBox()); - fltrRankbox = Gtk::manage (new Gtk::HBox()); - fltrLabelbox = Gtk::manage (new Gtk::HBox()); - - iUnRanked = new RTImage ("ratednot.png"); - igUnRanked = new RTImage ("ratednotg.png"); - bUnRanked = Gtk::manage( new Gtk::ToggleButton () ); - bUnRanked->set_active (false); - bUnRanked->set_image (*igUnRanked); - bUnRanked->set_relief (Gtk::RELIEF_NONE); - bUnRanked->set_tooltip_markup (M("FILEBROWSER_SHOWUNRANKHINT")); - bCateg[1] = bUnRanked->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bUnRanked, true)); - fltrRankbox->pack_start (*bUnRanked, Gtk::PACK_SHRINK); - bUnRanked->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); - - for (int i=0; i<5; i++) { - iranked[i] = new RTImage ("rated.png"); - igranked[i] = new RTImage ("grayrated.png"); - iranked[i]->show (); - igranked[i]->show (); - bRank[i] = Gtk::manage( new Gtk::ToggleButton () ); - bRank[i]->set_image (*igranked[i]); - bRank[i]->set_relief (Gtk::RELIEF_NONE); - fltrRankbox->pack_start (*bRank[i], Gtk::PACK_SHRINK); - bCateg[i+2] = bRank[i]->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bRank[i], true)); - bRank[i]->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); - } - - iUnCLabeled = new RTImage ("clabel0.png"); - igUnCLabeled = new RTImage ("cglabel0.png"); - bUnCLabeled = Gtk::manage(new Gtk::ToggleButton ()); - bUnCLabeled->set_active (false); - bUnCLabeled->set_image (*igUnCLabeled); - bUnCLabeled->set_relief (Gtk::RELIEF_NONE); - bUnCLabeled->set_tooltip_markup (M("FILEBROWSER_SHOWUNCOLORHINT")); - bCateg[7] = bUnCLabeled->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bUnCLabeled, true)); - fltrLabelbox->pack_start (*bUnCLabeled, Gtk::PACK_SHRINK); - bUnCLabeled->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); - - for (int i=0; i<5; i++) { - iCLabeled[i] = new RTImage (Glib::ustring::compose("%1%2%3","clabel",i+1,".png")); - igCLabeled[i] = new RTImage (Glib::ustring::compose("%1%2%3","cglabel",i+1,".png")); - iCLabeled[i]->show (); - igCLabeled[i]->show (); - bCLabel[i] = Gtk::manage(new Gtk::ToggleButton ()); - bCLabel[i]->set_image (*igCLabeled[i]); - bCLabel[i]->set_relief (Gtk::RELIEF_NONE); - fltrLabelbox->pack_start (*bCLabel[i], Gtk::PACK_SHRINK); - bCateg[i+8] = bCLabel[i]->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bCLabel[i], true)); - bCLabel[i]->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); - } - - fltrVbox1->pack_start (*fltrRankbox, Gtk::PACK_SHRINK,0); - fltrVbox1->pack_start (*fltrLabelbox, Gtk::PACK_SHRINK,0); - buttonBar->pack_start (*fltrVbox1, Gtk::PACK_SHRINK); - - bRank[0]->set_tooltip_markup (M("FILEBROWSER_SHOWRANK1HINT")); - bRank[1]->set_tooltip_markup (M("FILEBROWSER_SHOWRANK2HINT")); - bRank[2]->set_tooltip_markup (M("FILEBROWSER_SHOWRANK3HINT")); - bRank[3]->set_tooltip_markup (M("FILEBROWSER_SHOWRANK4HINT")); - bRank[4]->set_tooltip_markup (M("FILEBROWSER_SHOWRANK5HINT")); - - bCLabel[0]->set_tooltip_markup (M("FILEBROWSER_SHOWCOLORLABEL1HINT")); - bCLabel[1]->set_tooltip_markup (M("FILEBROWSER_SHOWCOLORLABEL2HINT")); - bCLabel[2]->set_tooltip_markup (M("FILEBROWSER_SHOWCOLORLABEL3HINT")); - bCLabel[3]->set_tooltip_markup (M("FILEBROWSER_SHOWCOLORLABEL4HINT")); - bCLabel[4]->set_tooltip_markup (M("FILEBROWSER_SHOWCOLORLABEL5HINT")); - - buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); - - fltrVbox2 = Gtk::manage (new Gtk::VBox()); - fltrEditedBox = Gtk::manage (new Gtk::HBox()); - fltrRecentlySavedBox = Gtk::manage (new Gtk::HBox()); - - // bEdited - iEdited[0] = new RTImage ("editednot-small.png"); - igEdited[0] = new RTImage ("editednotg-small.png"); - iEdited[1] = new RTImage ("edited-small.png"); - igEdited[1] = new RTImage ("editedg-small.png"); - for (int i=0; i<2; i++) { - iEdited[i]->show (); - bEdited[i] = Gtk::manage(new Gtk::ToggleButton ()); - bEdited[i]->set_active (false); - bEdited[i]->set_image (*igEdited[i]); - bEdited[i]->set_relief (Gtk::RELIEF_NONE); - fltrEditedBox->pack_start (*bEdited[i], Gtk::PACK_SHRINK); - //13, 14 - bCateg[i+13] = bEdited[i]->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bEdited[i], true)); - bEdited[i]->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); - } - bEdited[0]->set_tooltip_markup (M("FILEBROWSER_SHOWEDITEDNOTHINT")); - bEdited[1]->set_tooltip_markup (M("FILEBROWSER_SHOWEDITEDHINT")); - - // RecentlySaved - iRecentlySaved[0] = new RTImage ("savednot.png"); - igRecentlySaved[0] = new RTImage ("savednotg.png"); - iRecentlySaved[1] = new RTImage ("saved.png"); - igRecentlySaved[1] = new RTImage ("savedg.png"); - for (int i=0; i<2; i++) { - iRecentlySaved[i]->show (); - bRecentlySaved[i] = Gtk::manage(new Gtk::ToggleButton ()); - bRecentlySaved[i]->set_active (false); - bRecentlySaved[i]->set_image (*igRecentlySaved[i]); - bRecentlySaved[i]->set_relief (Gtk::RELIEF_NONE); - fltrRecentlySavedBox->pack_start (*bRecentlySaved[i], Gtk::PACK_SHRINK); - //15, 16 - bCateg[i+15] = bRecentlySaved[i]->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bRecentlySaved[i], true)); - bRecentlySaved[i]->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); - } - bRecentlySaved[0]->set_tooltip_markup (M("FILEBROWSER_SHOWRECENTLYSAVEDNOTHINT")); - bRecentlySaved[1]->set_tooltip_markup (M("FILEBROWSER_SHOWRECENTLYSAVEDHINT")); - - fltrVbox2->pack_start (*fltrEditedBox, Gtk::PACK_SHRINK,0); - fltrVbox2->pack_start (*fltrRecentlySavedBox, Gtk::PACK_SHRINK,0); - buttonBar->pack_start (*fltrVbox2, Gtk::PACK_SHRINK); - - buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); - - // Trash - iTrashEmpty = new RTImage("trash-show-empty.png") ; - iTrashFull = new RTImage("trash-show-full.png") ; - - bTrash = Gtk::manage( new Gtk::ToggleButton () ); - bTrash->set_image (*iTrashEmpty); - bTrash->set_relief (Gtk::RELIEF_NONE); - bTrash->set_tooltip_markup (M("FILEBROWSER_SHOWTRASHHINT")); - bCateg[17] = bTrash->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bTrash, true)); - bTrash->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); - - iNotTrash = new RTImage("trash-hide-deleted.png") ; - - bNotTrash = Gtk::manage( new Gtk::ToggleButton () ); - bNotTrash->set_image (*iNotTrash); - bNotTrash->set_relief (Gtk::RELIEF_NONE); - bNotTrash->set_tooltip_markup (M("FILEBROWSER_SHOWNOTTRASHHINT")); - bCateg[18] = bNotTrash->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bNotTrash, true)); - bNotTrash->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); - - buttonBar->pack_start (*bTrash, Gtk::PACK_SHRINK); - buttonBar->pack_start (*bNotTrash, Gtk::PACK_SHRINK); - buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); - fileBrowser->trash_changed().connect( sigc::mem_fun(*this, &FileCatalog::trashChanged) ); - - // 0 - bFilterClear - // 1 - bUnRanked - // 2 - bRank[0] - // 3 - bRank[1] - // 4 - bRank[2] - // 5 - bRank[3] - // 6 - bRank[4] - // 7 - bUnCLabeled - // 8 - bCLabel[0] - // 9 - bCLabel[1] - // 10 - bCLabel[2] - // 11 - bCLabel[3] - // 12 - bCLabel[4] - // 13 - bEdited[0] - // 14 - bEdited[1] - // 15 - bRecentlySaved[0] - // 16 - bRecentlySaved[1] - // 17 - bTrash - // 18 - bNotTrash - - categoryButtons[0] = bFilterClear; - categoryButtons[1] = bUnRanked; - for (int i=0; i<5; i++){ categoryButtons[i+2] = bRank[i];} - categoryButtons[7] = bUnCLabeled; - for (int i=0; i<5; i++){ categoryButtons[i+8] = bCLabel[i];} - for (int i=0; i<2; i++){ categoryButtons[i+13] = bEdited[i];} - for (int i=0; i<2; i++){ categoryButtons[i+15] = bRecentlySaved[i];} - categoryButtons[17] = bTrash; - categoryButtons[18] = bNotTrash; - - exifInfo = Gtk::manage(new Gtk::ToggleButton ()); - exifInfo->set_image (*Gtk::manage(new RTImage ("info.png"))); - exifInfo->set_relief (Gtk::RELIEF_NONE); - exifInfo->set_tooltip_markup (M("FILEBROWSER_SHOWEXIFINFO")); - exifInfo->set_active( options.showFileNames ); - exifInfo->signal_toggled().connect(sigc::mem_fun(*this, &FileCatalog::exifInfoButtonToggled)); - buttonBar->pack_start (*exifInfo, Gtk::PACK_SHRINK); - - // thumbnail zoom - Gtk::HBox* zoomBox = Gtk::manage( new Gtk::HBox () ); - zoomInButton = Gtk::manage( new Gtk::Button () ); - zoomInButton->set_image (*Gtk::manage(new RTImage ("gtk-zoom-in.png"))); - zoomInButton->signal_pressed().connect (sigc::mem_fun(*this, &FileCatalog::zoomIn)); - zoomInButton->set_relief (Gtk::RELIEF_NONE); - zoomInButton->set_tooltip_markup (M("FILEBROWSER_ZOOMINHINT")); - zoomBox->pack_end (*zoomInButton, Gtk::PACK_SHRINK); - zoomOutButton = Gtk::manage( new Gtk::Button () ); - zoomOutButton->set_image (*Gtk::manage(new RTImage ("gtk-zoom-out.png"))); - zoomOutButton->signal_pressed().connect (sigc::mem_fun(*this, &FileCatalog::zoomOut)); - zoomOutButton->set_relief (Gtk::RELIEF_NONE); - zoomOutButton->set_tooltip_markup (M("FILEBROWSER_ZOOMOUTHINT")); - zoomBox->pack_end (*zoomOutButton, Gtk::PACK_SHRINK); - - buttonBar->pack_start (*zoomBox, Gtk::PACK_SHRINK); - buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); - - //iRightArrow = new RTImage("right.png"); - //iRightArrow_red = new RTImage("right_red.png"); - - // if it IS a single row toolbar - if (options.FileBrowserToolbarSingleRow) buttonBar->pack_start (*hbToolBar1, Gtk::PACK_EXPAND_WIDGET,0); - - tbRightPanel_1 = new Gtk::ToggleButton (); - iRightPanel_1_Show = new RTImage("panel-to-left.png"); - iRightPanel_1_Hide = new RTImage("panel-to-right.png"); - - tbRightPanel_1->set_relief(Gtk::RELIEF_NONE); - tbRightPanel_1->set_active (true); - tbRightPanel_1->set_tooltip_markup (M("MAIN_TOOLTIP_SHOWHIDERP1")); - tbRightPanel_1->set_image (*iRightPanel_1_Hide); - tbRightPanel_1->signal_toggled().connect( sigc::mem_fun(*this, &FileCatalog::tbRightPanel_1_toggled) ); - buttonBar->pack_end (*tbRightPanel_1, Gtk::PACK_SHRINK); - - buttonBar->pack_end (*coarsePanel, Gtk::PACK_SHRINK); - buttonBar->pack_end (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK, 4); - buttonBar->pack_end (*toolBar, Gtk::PACK_SHRINK); - buttonBar->pack_end (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK, 4); - - // add default panel - hBox = Gtk::manage( new Gtk::HBox () ); - hBox->show (); - hBox->pack_end (*fileBrowser); - fileBrowser->applyFilter (getFilter()); // warning: can call this only after all objects used in getFilter (e.g. Query) are instantiated - //printf("FileCatalog::FileCatalog fileBrowser->applyFilter (getFilter())\n"); - pack_start (*hBox); - - enabled = true; - - lastScrollPos = 0; - for (int i=0; i<18; i++) { - hScrollPos[i] = 0; - vScrollPos[i] = 0; - } - - selectedDirectory = ""; -#ifdef WIN32 - wdMonitor = NULL; -#endif -} - -FileCatalog::~FileCatalog(){ - for (int i=0; i<5; i++) { - delete iranked[i]; - delete igranked[i]; - delete iCLabeled[i]; - delete igCLabeled[i]; - } - for (int i=0; i<2; i++) { - delete iEdited[i]; - delete igEdited[i]; - delete iRecentlySaved[i]; - delete igRecentlySaved[i]; - } - delete iFilterClear; - delete igFilterClear; - delete iUnRanked; - delete igUnRanked; - delete iUnCLabeled; - delete igUnCLabeled; - delete iTrashEmpty; - delete iTrashFull; - delete iRefreshWhite; - delete iRefreshRed; - delete iQueryClear; - delete iLeftPanel_1_Show; - delete iLeftPanel_1_Hide; - delete iRightPanel_1_Show; - delete iRightPanel_1_Hide; -} - -bool FileCatalog::capture_event(GdkEventButton* event){ - // need to record modifiers on the button press, because signal_toggled does not pass the event. - modifierKey = event->state; - return false; -} - -void FileCatalog::exifInfoButtonToggled() -{ - if (inTabMode) - options.filmStripShowFileNames = exifInfo->get_active(); - else - options.showFileNames = exifInfo->get_active(); - fileBrowser->refreshThumbImages (); -} - -void FileCatalog::on_realize() { - - Gtk::VBox::on_realize(); - Pango::FontDescription fontd = get_pango_context()->get_font_description (); - fileBrowser->get_pango_context()->set_font_description (fontd); -// batchQueue->get_pango_context()->set_font_description (fontd); -} - -void FileCatalog::closeDir () { - - if (filterPanel) - filterPanel->set_sensitive (false); - - if (exportPanel) - exportPanel->set_sensitive (false); - -#ifndef WIN32 - if (dirMonitor) - dirMonitor->cancel (); -#else - if (wdMonitor) { - delete wdMonitor; - wdMonitor = NULL; - } -#endif - - // ignore old requests - ++selectedDirectoryId; - - // terminate thumbnail preview loading - previewLoader->removeAllJobs (); - - // terminate thumbnail updater - thumbImageUpdater->removeAllJobs (); - - // remove entries - selectedDirectory = ""; - fileBrowser->close (); - fileNameList.clear (); - - { - MyMutex::MyLock lock(dirEFSMutex); - dirEFS.clear (); - } - hasValidCurrentEFS = false; - redrawAll (); -} - -std::vector FileCatalog::getFileList () { - - std::vector names; - Glib::RefPtr dir = Gio::File::create_for_path (selectedDirectory); - safe_build_file_list (dir, names, selectedDirectory, &(options.parsedExtensions)); -// Issue 2406 std::sort (names.begin(), names.end()); - return names; -} - -void FileCatalog::dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile) { - - try { - Glib::RefPtr dir = Gio::File::create_for_path (dirname); - - if (!dir) - return; - closeDir (); - previewsToLoad = 0; - previewsLoaded = 0; - // if openfile exists, we have to open it first (it is a command line argument) - if (!openfile.empty()) - addAndOpenFile (openfile); - - selectedDirectory = dir->get_parse_name(); - //printf("FileCatalog::dirSelected selectedDirectory = %s\n",selectedDirectory.c_str()); - BrowsePath->set_text (selectedDirectory); - buttonBrowsePath->set_image (*iRefreshWhite); - fileNameList = getFileList (); - - for (unsigned int i=0; i f = Gio::File::create_for_path(fileNameList[i]); - if (f->get_parse_name() != openfile) // if we opened a file at the beginning don't add it again - checkAndAddFile (f); - } - - _refreshProgressBar (); - if (previewsToLoad == 0) { - filepanel->loadingThumbs(M("PROGRESSBAR_NOIMAGES"),0); - } else { - filepanel->loadingThumbs(M("PROGRESSBAR_LOADINGTHUMBS"),0); - } - -#ifdef WIN32 - wdMonitor = new WinDirMonitor (selectedDirectory, this); -#else - dirMonitor = dir->monitor_directory (); - dirMonitor->signal_changed().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::on_dir_changed), false)); -#endif - } - catch (Glib::Exception& ex) { - std::cout << ex.what(); - } -} - -void FileCatalog::enableTabMode(bool enable) { - inTabMode = enable; - - if (enable) { - if (options.showFilmStripToolBar) - showToolBar(); - else - hideToolBar(); - exifInfo->set_active( options.filmStripShowFileNames ); - - } - else { - buttonBar->show(); - hbToolBar1->show(); - exifInfo->set_active( options.showFileNames ); - } - fileBrowser->enableTabMode(inTabMode); - - redrawAll(); -} - -void FileCatalog::_refreshProgressBar () { - // In tab mode, no progress bar at all - // Also mention that this progress bar only measures the FIRST pass (quick thumbnails) - // The second, usually longer pass is done multithreaded down in the single entries and is NOT measured by this - if (!inTabMode) { - GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected - - Gtk::Notebook *nb =(Gtk::Notebook *)(filepanel->get_parent()); - Gtk::Box* hbb=NULL; - Gtk::Label *label=NULL; - if( options.mainNBVertical ) - hbb = Gtk::manage (new Gtk::VBox ()); - else - hbb = Gtk::manage (new Gtk::HBox ()); - if (!previewsToLoad ) { - hbb->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU))); - int filteredCount = min(fileBrowser->getNumFiltered(),previewsLoaded); - - label = Gtk::manage (new Gtk::Label (M("MAIN_FRAME_FILEBROWSER")+ - (filteredCount!=previewsLoaded ? " ["+ Glib::ustring::format(filteredCount)+"/" : " (") - + Glib::ustring::format(previewsLoaded) + - (filteredCount!=previewsLoaded ? "]" : ")"))); - } else { - hbb->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::FIND, Gtk::ICON_SIZE_MENU))); - label = Gtk::manage (new Gtk::Label (M("MAIN_FRAME_FILEBROWSER")+" [" +Glib::ustring::format(std::fixed, std::setprecision(0), std::setw(3), (double)previewsLoaded / previewsToLoad*100 )+"%]" )); - filepanel->loadingThumbs("",(double)previewsLoaded / previewsToLoad); - } - if( options.mainNBVertical ) - label->set_angle(90); - hbb->pack_start (*label); - hbb->set_spacing (2); - hbb->set_tooltip_markup (M("MAIN_FRAME_FILEBROWSER_TOOLTIP")); - hbb->show_all (); - nb->set_tab_label(*filepanel,*hbb); - } -} - -int refreshProgressBarUI (void* data) { - (static_cast(data))->_refreshProgressBar (); - return 0; -} - -void FileCatalog::filterApplied() { - g_idle_add (refreshProgressBarUI, this); -} - - -void FileCatalog::previewReady (int dir_id, FileBrowserEntry* fdn) { - - if ( dir_id != selectedDirectoryId ) - return; - - // put it into the "full directory" browser - fdn->setImageAreaToolListener (iatlistener); - fileBrowser->addEntry (fdn); - - // update exif filter settings (minimal & maximal values of exif tags, cameras, lenses, etc...) - const CacheImageData* cfs = fdn->thumbnail->getCacheImageData(); - - { - MyMutex::MyLock lock(dirEFSMutex); - if (cfs->exifValid) { - if (cfs->fnumber < dirEFS.fnumberFrom) - dirEFS.fnumberFrom = cfs->fnumber; - if (cfs->fnumber > dirEFS.fnumberTo) - dirEFS.fnumberTo = cfs->fnumber; - if (cfs->shutter < dirEFS.shutterFrom) - dirEFS.shutterFrom = cfs->shutter; - if (cfs->shutter > dirEFS.shutterTo) - dirEFS.shutterTo = cfs->shutter; - if (cfs->iso>0 && (int)cfs->iso < dirEFS.isoFrom) - dirEFS.isoFrom = (int)cfs->iso; - if (cfs->iso>0 && (int)cfs->iso > dirEFS.isoTo) - dirEFS.isoTo = (int)cfs->iso; - if (cfs->focalLen < dirEFS.focalFrom) - dirEFS.focalFrom = cfs->focalLen; - if (cfs->focalLen > dirEFS.focalTo) - dirEFS.focalTo = cfs->focalLen; - } - dirEFS.filetypes.insert (cfs->filetype); - dirEFS.cameras.insert (cfs->getCamera()); - dirEFS.lenses.insert (cfs->lens); - dirEFS.expcomp.insert (cfs->expcomp); - } - - previewsLoaded++; - - g_idle_add (refreshProgressBarUI, this); -} - -int prevfinished (void* data) { - (static_cast(data))->previewsFinishedUI (); - return 0; -} - -// Called within GTK UI thread -void FileCatalog::previewsFinishedUI () { - - { - GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected - redrawAll (); - previewsToLoad = 0; - - if (filterPanel) { - filterPanel->set_sensitive (true); - if ( !hasValidCurrentEFS ){ - MyMutex::MyLock lock(dirEFSMutex); - currentEFS = dirEFS; - filterPanel->setFilter ( dirEFS,true ); - }else { - filterPanel->setFilter ( currentEFS,false ); - } - } - - if (exportPanel) - exportPanel->set_sensitive (true); - - // restart anything that might have been loaded low quality - fileBrowser->refreshQuickThumbImages(); - fileBrowser->applyFilter (getFilter()); // refresh total image count - _refreshProgressBar(); - } - filepanel->loadingThumbs(M("PROGRESSBAR_READY"),0); - - if (!imageToSelect_fname.empty()){ - fileBrowser->selectImage(imageToSelect_fname); - imageToSelect_fname = ""; - } - - if (!refImageForOpen_fname.empty() && actionNextPrevious!=NAV_NONE){ - fileBrowser->openNextPreviousEditorImage(refImageForOpen_fname,actionNextPrevious); - refImageForOpen_fname = ""; - actionNextPrevious = NAV_NONE; - } -} - -void FileCatalog::previewsFinished (int dir_id) { - - if ( dir_id != selectedDirectoryId ) - { - return; - } - - if (!hasValidCurrentEFS) { - MyMutex::MyLock lock(dirEFSMutex); - currentEFS = dirEFS; - } - - g_idle_add (prevfinished, this); -} - -void FileCatalog::setEnabled (bool e) { - enabled = e; -} - -void FileCatalog::redrawAll () { - fileBrowser->queue_draw (); -} - -void FileCatalog::refreshThumbImages () { - fileBrowser->refreshThumbImages (); -} - -void FileCatalog::refreshHeight () { - int newHeight = fileBrowser->getEffectiveHeight(); - if (newHeight < 5) { // This may occure if there's no thumbnail. - int w, h; - get_size_request(w, h); - newHeight = h; - } - if (hbToolBar1->is_visible() && !options.FileBrowserToolbarSingleRow) - newHeight += hbToolBar1->get_height(); - if (buttonBar->is_visible()) - newHeight += buttonBar->get_height(); - set_size_request(0, newHeight+2); // HOMBRE: yeah, +2, there's always 2 pixels missing... sorry for this dirty hack O:) -} - -void FileCatalog::_openImage (std::vector tmb) { - - if (enabled && listener!=NULL) { - bool continueToLoad=true; - for (size_t i=0; i< tmb.size() && continueToLoad; i++) { - // Open the image here, and stop if in Single Editor mode, or if an image couldn't - // be opened, would it be because the file doesn't exist or because of lack of RAM - if( !(listener->fileSelected (tmb[i])) && !options.tabbedUI ) - continueToLoad = false; - tmb[i]->decreaseRef (); - } - } -} - -struct FCOIParams { - FileCatalog* catalog; - std::vector tmb; -}; - -int openRequestedUI (void* p) { - FCOIParams* params = static_cast(p); - params->catalog->_openImage (params->tmb); - delete params; - - return 0; -} - -void FileCatalog::openRequested (std::vector tmb) { - - FCOIParams* params = new FCOIParams; - params->catalog = this; - params->tmb = tmb; - for (size_t i=0; iincreaseRef (); - g_idle_add (openRequestedUI, params); -} - -void FileCatalog::deleteRequested (std::vector tbe, bool inclBatchProcessed) { - - if (tbe.empty()) - return; - - Gtk::MessageDialog msd (M("FILEBROWSER_DELETEDLGLABEL"), true, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true); - msd.set_secondary_text(Glib::ustring::compose ( inclBatchProcessed ? M("FILEBROWSER_DELETEDLGMSGINCLPROC") : M("FILEBROWSER_DELETEDLGMSG"), tbe.size()), true); - - if (msd.run()==Gtk::RESPONSE_YES) { - for (unsigned int i=0; ifilename; - // remove from browser - FileBrowserEntry* t = fileBrowser->delEntry (fname); -// t->thumbnail->decreaseRef (); - delete t; - // remove from cache - cacheMgr->deleteEntry (fname); - // delete from file system - safe_g_remove (fname); - // delete paramfile if found - safe_g_remove (Glib::ustring(fname+paramFileExtension)); - safe_g_remove (Glib::ustring(removeExtension(fname)+paramFileExtension)); - // delete .thm file - safe_g_remove (Glib::ustring(removeExtension(fname)+".thm")); - safe_g_remove (Glib::ustring(removeExtension(fname)+".THM")); - - if (inclBatchProcessed) { - Glib::ustring procfName = Glib::ustring::compose ("%1.%2", BatchQueue::calcAutoFileNameBase(fname), options.saveFormatBatch.format); - if (safe_file_test (procfName, Glib::FILE_TEST_EXISTS)) safe_g_remove (procfName); - - // delete paramfile if found - Glib::ustring procfNameParamFile = Glib::ustring::compose ("%1.%2.out%3", BatchQueue::calcAutoFileNameBase(fname), options.saveFormatBatch.format, paramFileExtension); - if (safe_file_test (procfNameParamFile, Glib::FILE_TEST_EXISTS)) safe_g_remove (procfNameParamFile); - } - - previewsLoaded--; - } - - _refreshProgressBar(); - redrawAll (); - } -} - - -void FileCatalog::copyMoveRequested (std::vector tbe, bool moveRequested) { - - if (tbe.empty()) - return; - - - Glib::ustring fc_title; - if (moveRequested) fc_title=M("FILEBROWSER_POPUPMOVETO"); - else fc_title=M("FILEBROWSER_POPUPCOPYTO"); - Gtk::FileChooserDialog fc(fc_title,Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER ); - fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); - fc.add_button( Gtk::StockID("gtk-ok"), Gtk::RESPONSE_OK); - // open dialog at the 1-st file's path - fc.set_filename(tbe[0]->filename); - //!!! TODO prevent dialog closing on "enter" key press - - bool filecopymovecomplete; - int i_copyindex; - - if( fc.run() == Gtk::RESPONSE_OK ){ - Glib::ustring dest_Dir = fc.get_current_folder(); - - // iterate through selected files - for (unsigned int i=0; ifilename; - Glib::ustring src_Dir = Glib::path_get_dirname(src_fPath); - Glib::RefPtr src_file = Gio::File::create_for_path ( src_fPath ); - if( !src_file ) continue; // if file is missing - skip it - - Glib::ustring fname=src_file->get_basename(); - Glib::ustring fname_noExt = removeExtension(fname); - Glib::ustring fname_Ext = getExtension(fname); - - // construct destination File Paths - Glib::ustring dest_fPath = Glib::build_filename (dest_Dir, fname); - Glib::ustring dest_fPath_param= dest_fPath + paramFileExtension; - - if (moveRequested && (src_Dir==dest_Dir)) continue; - /* comparison of src_Dir and dest_Dir is done per image for compatibility with - possible future use of Collections as source where each file's source path may be different.*/ - - filecopymovecomplete = false; - i_copyindex = 1; - while(!filecopymovecomplete){ - // check for filename conflicts at destination - prevent overwriting (actually RT will crash on overwriting attempt) - if (!safe_file_test(dest_fPath, Glib::FILE_TEST_EXISTS) && !safe_file_test(dest_fPath_param, Glib::FILE_TEST_EXISTS)){ - // copy/move file to destination - Glib::RefPtr dest_file = Gio::File::create_for_path ( dest_fPath ); - if (moveRequested) { - // move file - src_file->move(dest_file); - // re-attach cache files - cacheMgr->renameEntry (src_fPath, tbe[i]->thumbnail->getMD5(), dest_fPath); - // remove from browser - fileBrowser->delEntry (src_fPath); - - previewsLoaded--; - } - else - src_file->copy(dest_file); - - - // attempt to copy/move paramFile only if it exist next to the src - Glib::RefPtr scr_param = Gio::File::create_for_path ( src_fPath + paramFileExtension ); - - if (safe_file_test( src_fPath + paramFileExtension, Glib::FILE_TEST_EXISTS)){ - Glib::RefPtr dest_param = Gio::File::create_for_path ( dest_fPath_param); - // copy/move paramFile to destination - if (moveRequested){ - if (safe_file_test( dest_fPath + paramFileExtension, Glib::FILE_TEST_EXISTS)){ - // profile already got copied to destination from cache after cacheMgr->renameEntry - // delete source profile as cleanup - safe_g_remove (src_fPath + paramFileExtension); - } - else - scr_param->move(dest_param); - } - else - scr_param->copy(dest_param); - } - filecopymovecomplete = true; - } - else{ - // adjust destination fname to avoid conflicts (append "_", preserve extension) - Glib::ustring dest_fname = Glib::ustring::compose("%1%2%3%4%5",fname_noExt,"_",i_copyindex,".",fname_Ext); - // re-construct destination File Paths - dest_fPath = Glib::build_filename (dest_Dir, dest_fname); - dest_fPath_param= dest_fPath + paramFileExtension; - i_copyindex++; - } - }//while - } // i tbe, bool fastmode) { - - if (listener) { - std::vector entries; - - // TODO: (HOMBRE) should we still use parallelization here, now that thumbnails are processed asynchronously...? - //#pragma omp parallel for ordered - for (size_t i=0; ithumbnail; - rtengine::procparams::ProcParams params = th->getProcParams(); - - // if fast mode is selected, override (disable) params - // controlling time and resource consuming tasks - // and also those which effect is not pronounced after reducing the image size - // TODO!!! could expose selections below via preferences - if (fastmode){ - if (options.fastexport_bypass_sharpening ) params.sharpening.enabled = false; - if (options.fastexport_bypass_sharpenEdge ) params.sharpenEdge.enabled = false; - if (options.fastexport_bypass_sharpenMicro ) params.sharpenMicro.enabled = false; - //if (options.fastexport_bypass_lumaDenoise ) params.lumaDenoise.enabled = false; - //if (options.fastexport_bypass_colorDenoise ) params.colorDenoise.enabled = false; - if (options.fastexport_bypass_defringe ) params.defringe.enabled = false; - if (options.fastexport_bypass_dirpyrDenoise ) params.dirpyrDenoise.enabled = false; - if (options.fastexport_bypass_sh_hq ) params.sh.hq = false; - if (options.fastexport_bypass_dirpyrequalizer ) params.dirpyrequalizer.enabled = false; - if (options.fastexport_bypass_wavelet ) params.wavelet.enabled = false; - //if (options.fastexport_bypass_raw_bayer_all_enhance ) params.raw.bayersensor.all_enhance = false; - if (options.fastexport_bypass_raw_bayer_dcb_iterations ) params.raw.bayersensor.dcb_iterations = 0; - if (options.fastexport_bypass_raw_bayer_dcb_enhance ) params.raw.bayersensor.dcb_enhance = false; - if (options.fastexport_bypass_raw_bayer_lmmse_iterations) params.raw.bayersensor.lmmse_iterations = 0; - if (options.fastexport_bypass_raw_bayer_linenoise ) params.raw.bayersensor.linenoise = 0; - if (options.fastexport_bypass_raw_bayer_greenthresh ) params.raw.bayersensor.greenthresh = 0; - if (options.fastexport_bypass_raw_ccSteps ) {params.raw.bayersensor.ccSteps = params.raw.xtranssensor.ccSteps = 0;} - if (options.fastexport_bypass_raw_ca ) {params.raw.ca_autocorrect = false; params.raw.cared=0; params.raw.cablue=0;} - if (options.fastexport_bypass_raw_df ) {params.raw.df_autoselect = false; params.raw.dark_frame="";} - if (options.fastexport_bypass_raw_ff ) {params.raw.ff_AutoSelect = false; params.raw.ff_file="";} - params.raw.bayersensor.method = options.fastexport_raw_bayer_method ; - params.raw.xtranssensor.method = options.fastexport_raw_xtrans_method; - params.icm.input = options.fastexport_icm_input ; - params.icm.working = options.fastexport_icm_working ; - params.icm.output = options.fastexport_icm_output ; - params.icm.gamma = options.fastexport_icm_gamma ; - params.resize.enabled = options.fastexport_resize_enabled ; - params.resize.scale = options.fastexport_resize_scale ; - params.resize.appliesTo = options.fastexport_resize_appliesTo ; - params.resize.method = options.fastexport_resize_method ; - params.resize.dataspec = options.fastexport_resize_dataspec ; - params.resize.width = options.fastexport_resize_width ; - params.resize.height = options.fastexport_resize_height ; - } - - rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType()==FT_Raw, params); - - int pw; - int ph = BatchQueue::calcMaxThumbnailHeight(); - th->getThumbnailSize (pw, ph); - - // processThumbImage is the processing intensive part, but adding to queue must be ordered - //#pragma omp ordered - //{ - BatchQueueEntry* bqh = new BatchQueueEntry (pjob, params, fbe->filename, pw, ph, th); - entries.push_back(bqh); - //} - } - - listener->addBatchQueueJobs( entries ); - } -} - -void FileCatalog::exportRequested (){ - -} - -void FileCatalog::setExportPanel (ExportPanel* expanel) { - - exportPanel = expanel; - exportPanel->set_sensitive (false); - exportPanel->setExportPanelListener (this); - fileBrowser->setExportPanel(expanel); -} - -void FileCatalog::renameRequested (std::vector tbe) { - - bool success; - - RenameDialog* renameDlg = new RenameDialog ((Gtk::Window*)get_toplevel()); - - for (size_t i=0; iinitName (Glib::path_get_basename (tbe[i]->filename), tbe[i]->thumbnail->getCacheImageData()); - - Glib::ustring ofname = tbe[i]->filename; - Glib::ustring dirName = Glib::path_get_dirname (tbe[i]->filename); - Glib::ustring baseName = Glib::path_get_basename (tbe[i]->filename); - - success = false; - do { - if (renameDlg->run ()== Gtk::RESPONSE_OK) { - Glib::ustring nBaseName = renameDlg->getNewName (); - // if path has directory components, exit - if (Glib::path_get_dirname (nBaseName) != ".") - continue; - // if no extension is given, concatenate the extension of the original file - Glib::ustring ext = getExtension (nBaseName); - if (ext.empty()) - nBaseName += "." + getExtension (baseName); - Glib::ustring nfname = Glib::build_filename (dirName, nBaseName); - - /* check if filename already exists*/ - if (safe_file_test (nfname, Glib::FILE_TEST_EXISTS)) { - Glib::ustring msg_ = Glib::ustring("") + nfname + ": " + M("MAIN_MSG_ALREADYEXISTS") + ""; - Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); - msgd.run (); - } - else { - success = true; - if (!safe_g_rename (ofname, nfname)) { - cacheMgr->renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); - safe_g_remove(ofname + paramFileExtension); - reparseDirectory (); - } - } - } - else - success = true; - } while (!success); - renameDlg->hide (); - } - delete renameDlg; -/* // ask for new file name - Gtk::Dialog dialog (M("FILEBROWSER_RENAMEDLGLABEL"), *((Gtk::Window*)get_toplevel()), true, true); - - dialog.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); - dialog.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - - Gtk::Label l; - dialog.get_vbox()->pack_start (l, Gtk::PACK_SHRINK); - - Gtk::Entry nfentry; - - dialog.get_vbox()->pack_start (nfentry, Gtk::PACK_SHRINK); - dialog.get_vbox()->show_all (); - - nfentry.set_activates_default (true); - dialog.set_default_response (Gtk::RESPONSE_OK); - - for (int i=0; ifilename; - Glib::ustring dirName = Glib::path_get_dirname (tbe[i]->filename); - Glib::ustring baseName = Glib::path_get_basename (tbe[i]->filename); - - l.set_markup (Glib::ustring("") + Glib::ustring::compose (M("FILEBROWSER_RENAMEDLGMSG"), baseName) + Glib::ustring("")); - nfentry.set_text (baseName); - nfentry.select_region (0, baseName.size()); - - if (dialog.run ()== Gtk::RESPONSE_OK) { - Glib::ustring nBaseName = nfentry.get_text (); - // if path has directory components, exit - if (Glib::path_get_dirname (nBaseName) != ".") - continue; - // if no extension is given, concatenate the extension of the original file - if (nBaseName.find ('.')==nBaseName.npos) { - size_t lastdot = baseName.find_last_of ('.'); - nBaseName += "." + (lastdot!=Glib::ustring::npos ? baseName.substr (lastdot+1) : ""); - } - Glib::ustring nfname = Glib::build_filename (dirName, nBaseName); - if (!safe_g_rename (ofname, nfname)) { - cacheMgr->renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); - // the remaining part (removing old and adding new entry) is done by the directory monitor - reparseDirectory (); -// on_dir_changed (Gio::File::create_for_path (nfname), Gio::File::create_for_path (nfname), Gio::FILE_MONITOR_EVENT_CHANGED, true); - } - } - } - */ -} - -void FileCatalog::clearFromCacheRequested (std::vector tbe, bool leavenotrace) { - - if (tbe.empty()) - return; - - for (unsigned int i=0; ifilename; - // remove from cache - cacheMgr->clearFromCache (fname,leavenotrace); - } -} - -void FileCatalog::categoryButtonToggled (Gtk::ToggleButton* b, bool isMouseClick) { - - //was control key pressed - bool control_down = modifierKey & GDK_CONTROL_MASK; - - //was shift key pressed - bool shift_down = modifierKey & GDK_SHIFT_MASK; - - // The event is process here, we can clear modifierKey now, it'll be set again on the next even - modifierKey = 0; - - const int numCateg = sizeof(bCateg) / sizeof(bCateg[0]); - const int numButtons = sizeof(categoryButtons) / sizeof(categoryButtons[0]); - - for (int i=0; iset_active(!b->get_active()); - - //if both control and shift keys were pressed, do nothing - if (!(control_down && shift_down)) { - - fileBrowser->getScrollPosition (hScrollPos[lastScrollPos], vScrollPos[lastScrollPos]); - - //we look how many stars are already toggled on, if any - int toggled_stars_count=0, buttons=0, start_star=0, toggled_button=0; - - for (int i=0; iget_active()) { - if (i>0 && i<17) { - toggled_stars_count ++; - start_star = i; - } - buttons |= (1 << i); - } - if (categoryButtons[i] == b) toggled_button = i; - } - - // if no modifier key is pressed, - if (!(control_down || shift_down)) { - // if we're deselecting non-trashed - if (toggled_button == 18 && (buttons & (1 << toggled_button))) { - categoryButtons[0]->set_active (true); - for (int i=1; iset_active (false); - } - // if we're deselecting the only star still active - else if (toggled_stars_count == 1 && (buttons & (1 << toggled_button))) { - // activate clear-filters - categoryButtons[0]->set_active (true); - // deactivate the toggled filter - categoryButtons[toggled_button]->set_active (false); - } - // if we're deselecting trash - else if (toggled_button == 17 && (buttons & (1 << toggled_button))) { - categoryButtons[0]->set_active (true); - categoryButtons[17]->set_active (false); - } - else { - // activate the toggled filter, deactivate the rest - for (int i=0; iset_active (i==toggled_button); - } - } - //modifier key allowed only for stars and color labels... - else if (toggled_button>0 && toggled_button<17) { - if (control_down) { - //control is pressed - if (toggled_stars_count == 1 && (buttons & (1 << toggled_button))) { - //we're deselecting the only star still active, so we activate clear-filters - categoryButtons[0]->set_active(true); - //and we deselect the toggled star - categoryButtons[toggled_button]->set_active (false); - } - else if (toggled_stars_count >= 1) { - //we toggle the state of a star (eventually another one than the only one selected) - categoryButtons[toggled_button]->set_active(!categoryButtons[toggled_button]->get_active()); - } - else { - //no star selected - //we deselect the 2 non star filters - if (buttons & 1 ) categoryButtons[0]->set_active(false); - if (buttons & (1 << 17)) categoryButtons[17]->set_active(false); - //and we toggle on the star - categoryButtons[toggled_button]->set_active (true); - } - } - else { - //shift is pressed, only allowed if 0 or 1 star & labels is selected - if (!toggled_stars_count) { - //we deselect the 2 non star filters - if (buttons & 1 ) categoryButtons[0]->set_active(false); - if (buttons & (1 << 7)) categoryButtons[7]->set_active(false); - if (buttons & (1 << 13)) categoryButtons[13]->set_active(false); - if (buttons & (1 << 17)) categoryButtons[17]->set_active(false); - //and we set the start star to 1 (unrated images) - start_star = 1; - //we act as if one star were selected - toggled_stars_count = 1; - } - if (toggled_stars_count == 1) { - int current_star=min(start_star,toggled_button); - int last_star =max(start_star,toggled_button); - //we permute the start and the end star for the next loop - for (; current_star <= last_star; current_star++) { - //we toggle on all the star in the range - if (!(buttons & (1 << current_star))) categoryButtons[current_star]->set_active(true); - } - } - //if more than one star & color label is selected, do nothing - } - } - // ...or non-trashed with Control modifier - else if (toggled_button == 18 && control_down) - { - bNotTrash->set_active (!bNotTrash->get_active ()); - } - - bool active_now, active_before; - - // FilterClear: set the right images - // TODO: swapping FilterClear icon needs more work in categoryButtonToggled - /*active_now = bFilterClear->get_active(); - active_before = buttons & (1 << (0)); // 0 - if ( active_now && !active_before) bFilterClear->set_image (*iFilterClear); - else if (!active_now && active_before) bFilterClear->set_image (*igFilterClear);*/ - - // rank: set the right images - for (int i=0; i<5; i++) { - active_now = bRank[i]->get_active(); - active_before = buttons & (1 << (i+2)); // 2,3,4,5,6 - if ( active_now && !active_before) bRank[i]->set_image (*iranked[i]); - else if (!active_now && active_before) bRank[i]->set_image (*igranked[i]); - } - active_now = bUnRanked->get_active(); - active_before = buttons & (1 << (1)); // 1 - if ( active_now && !active_before) bUnRanked->set_image (*iUnRanked); - else if (!active_now && active_before) bUnRanked->set_image (*igUnRanked); - - // color labels: set the right images - for (int i=0; i<5; i++) { - active_now = bCLabel[i]->get_active(); - active_before = buttons & (1 << (i+8)); // 8,9,10,11,12 - if ( active_now && !active_before) bCLabel[i]->set_image (*iCLabeled[i]); - else if (!active_now && active_before) bCLabel[i]->set_image (*igCLabeled[i]); - } - active_now = bUnCLabeled->get_active(); - active_before = buttons & (1 << (7)); // 7 - if ( active_now && !active_before) bUnCLabeled->set_image (*iUnCLabeled); - else if (!active_now && active_before) bUnCLabeled->set_image (*igUnCLabeled); - - // Edited: set the right images - for (int i=0; i<2; i++) { - active_now = bEdited[i]->get_active(); - active_before = buttons & (1 << (i+13)); //13,14 - if ( active_now && !active_before) bEdited[i]->set_image (*iEdited[i]); - else if (!active_now && active_before) bEdited[i]->set_image (*igEdited[i]); - } - - // RecentlySaved: set the right images - for (int i=0; i<2; i++) { - active_now = bRecentlySaved[i]->get_active(); - active_before = buttons & (1 << (i+15));//15,16 - if ( active_now && !active_before) bRecentlySaved[i]->set_image (*iRecentlySaved[i]); - else if (!active_now && active_before) bRecentlySaved[i]->set_image (*igRecentlySaved[i]); - } - - fileBrowser->applyFilter (getFilter ()); - _refreshProgressBar(); - - //rearrange panels according to the selected filter - removeIfThere (hBox, trashButtonBox); - if (bTrash->get_active ()) - hBox->pack_start (*trashButtonBox, Gtk::PACK_SHRINK, 4); - hBox->queue_draw (); - - fileBrowser->setScrollPosition (hScrollPos[lastScrollPos], vScrollPos[lastScrollPos]); - } - - for (int i=0; iget_active () || bRank[0]->get_active () || bRank[1]->get_active () || bRank[2]->get_active () || bRank[3]->get_active () || bRank[4]->get_active (); - bool anyCLabelFilterActive = bUnCLabeled->get_active () || bCLabel[0]->get_active ()|| bCLabel[1]->get_active ()|| bCLabel[2]->get_active ()|| bCLabel[3]->get_active ()|| bCLabel[4]->get_active (); - bool anyEditedFilterActive = bEdited[0]->get_active() || bEdited[1]->get_active(); - bool anyRecentlySavedFilterActive = bRecentlySaved[0]->get_active() || bRecentlySaved[1]->get_active(); - const bool nonTrashedActive = bNotTrash->get_active(); - /* - * filter is setup in 2 steps - * Step 1: handle individual filters - */ - filter.showRanked[0] = bFilterClear->get_active() || bUnRanked->get_active () || bTrash->get_active () || nonTrashedActive || - anyCLabelFilterActive || anyEditedFilterActive || anyRecentlySavedFilterActive; - - filter.showCLabeled[0] = bFilterClear->get_active() || bUnCLabeled->get_active () || bTrash->get_active () || nonTrashedActive || - anyRankFilterActive || anyEditedFilterActive || anyRecentlySavedFilterActive; - - for (int i=1; i<=5; i++){ - filter.showRanked[i] = bFilterClear->get_active() || bRank[i-1]->get_active () || bTrash->get_active () || nonTrashedActive || - anyCLabelFilterActive || anyEditedFilterActive || anyRecentlySavedFilterActive; - - filter.showCLabeled[i] = bFilterClear->get_active() || bCLabel[i-1]->get_active () || bTrash->get_active () || nonTrashedActive || - anyRankFilterActive || anyEditedFilterActive || anyRecentlySavedFilterActive; - } - - for (int i=0; i<2; i++){ - filter.showEdited[i] = bFilterClear->get_active() || bEdited[i]->get_active () || bTrash->get_active () || nonTrashedActive || - anyRankFilterActive || anyCLabelFilterActive || anyRecentlySavedFilterActive; - - filter.showRecentlySaved[i] = bFilterClear->get_active() || bRecentlySaved[i]->get_active () || bTrash->get_active () || nonTrashedActive || - anyRankFilterActive || anyCLabelFilterActive || anyEditedFilterActive; - } - if( options.rtSettings.verbose ){ - printf ("\n**************** FileCatalog::getFilter *** AFTER STEP 1 \n"); - for (int i=0; i<=5; i++) printf ("filter.showRanked[%i] = %i\n",i,filter.showRanked[i]); - for (int i=0; i<=5; i++) printf ("filter.showCLabeled[%i] = %i\n",i,filter.showCLabeled[i]); - for (int i=0; i<2; i++) printf ("filter.showEdited[%i] = %i\n",i,filter.showEdited[i]); - for (int i=0; i<2; i++) printf ("filter.showRecentlySaved[%i] = %i\n",i,filter.showRecentlySaved[i]); - } - filter.multiselect = false; - - /* - * Step 2 - * handle the case when more than 1 filter is selected. This overrides values set in Step - * if no filters in a group are active, filter.show for each member of that group will be set to true - * otherwise they are set based on UI input - */ - if ((anyRankFilterActive && anyCLabelFilterActive ) || - (anyRankFilterActive && anyEditedFilterActive ) || - (anyRankFilterActive && anyRecentlySavedFilterActive ) || - (anyCLabelFilterActive && anyEditedFilterActive ) || - (anyCLabelFilterActive && anyRecentlySavedFilterActive ) || - (anyEditedFilterActive && anyRecentlySavedFilterActive) || - (nonTrashedActive && (anyRankFilterActive || anyCLabelFilterActive || anyEditedFilterActive || anyRecentlySavedFilterActive))){ - - filter.multiselect = true; - filter.showRanked[0] = anyRankFilterActive?bUnRanked->get_active ():true; - filter.showCLabeled[0] = anyCLabelFilterActive?bUnCLabeled->get_active ():true; - - for (int i=1; i<=5; i++){ - filter.showRanked[i] = anyRankFilterActive?bRank[i-1]->get_active ():true; - filter.showCLabeled[i] = anyCLabelFilterActive?bCLabel[i-1]->get_active ():true; - } - for (int i=0; i<2; i++){ - filter.showEdited[i] = anyEditedFilterActive?bEdited[i]->get_active():true; - filter.showRecentlySaved[i] = anyRecentlySavedFilterActive?bRecentlySaved[i]->get_active():true; - } - if( options.rtSettings.verbose ){ - printf ("\n**************** FileCatalog::getFilter *** AFTER STEP 2 \n"); - for (int i=0; i<=5; i++) printf ("filter.showRanked[%i] = %i\n",i,filter.showRanked[i]); - for (int i=0; i<=5; i++) printf ("filter.showCLabeled[%i] = %i\n",i,filter.showCLabeled[i]); - for (int i=0; i<2; i++) printf ("filter.showEdited[%i] = %i\n",i,filter.showEdited[i]); - for (int i=0; i<2; i++) printf ("filter.showRecentlySaved[%i] = %i\n",i,filter.showRecentlySaved[i]); - printf ("filter.multiselect = %i\n",filter.multiselect); - } - } - - - filter.showTrash = bTrash->get_active () || !bNotTrash->get_active (); - filter.showNotTrash = !bTrash->get_active (); - if (!filterPanel) - filter.exifFilterEnabled = false; - else { - if (!hasValidCurrentEFS) { - MyMutex::MyLock lock(dirEFSMutex); - filter.exifFilter = dirEFS; - } - else - filter.exifFilter = currentEFS; - filter.exifFilterEnabled = filterPanel->isEnabled (); - } - - //TODO add support for more query options. e.g by date, iso, f-number, etc - //TODO could use date:;iso: etc - // default will be filename - - /* // this is for safe execution if getFilter is called before Query object is instantiated - Glib::ustring tempQuery; - tempQuery=""; - if (Query) tempQuery = Query->get_text(); - */ - filter.queryString = Query->get_text(); // full query string from Query Entry - filter.queryFileName = Query->get_text(); // for now Query is only by file name - - return filter; -} - -void FileCatalog::filterChanged () { - //TODO !!! there is too many repetitive and unnecessary executions of - // " fileBrowser->applyFilter (getFilter()); " throughout the code - // this needs further analysis and cleanup - fileBrowser->applyFilter (getFilter()); - _refreshProgressBar(); -} - -void FileCatalog::reparseDirectory () { - - if (selectedDirectory.empty()) - return; - - if (!safe_file_test (selectedDirectory, Glib::FILE_TEST_IS_DIR)) { - closeDir (); - return; - } - - std::vector nfileNameList = getFileList (); - - // check if a thumbnailed file has been deleted - const std::vector& t = fileBrowser->getEntries (); - std::vector fileNamesToDel; - for (size_t i=0; ifilename, Glib::FILE_TEST_EXISTS)) - fileNamesToDel.push_back (t[i]->filename); - for (size_t i=0; idelEntry (fileNamesToDel[i]); - cacheMgr->deleteEntry (fileNamesToDel[i]); - } - - // check if a new file has been added - for (size_t i=0; i(cat))->reparseDirectory (); - return 0; -} - -void FileCatalog::winDirChanged () { - g_idle_add(winDirChangedUITread, this); -} - -#else - -void FileCatalog::on_dir_changed (const Glib::RefPtr& file, const Glib::RefPtr& other_file, Gio::FileMonitorEvent event_type, bool internal) { - - if (options.has_retained_extention(file->get_parse_name()) - && (event_type == Gio::FILE_MONITOR_EVENT_CREATED || event_type == Gio::FILE_MONITOR_EVENT_DELETED || event_type == Gio::FILE_MONITOR_EVENT_CHANGED)) { - if (!internal) { - GThreadLock lock; - reparseDirectory (); - } - else - reparseDirectory (); - } -} - -#endif - -void FileCatalog::checkAndAddFile (Glib::RefPtr file) { - - if (!file ) - return; - if( !file->query_exists()) - return; - Glib::RefPtr info = safe_query_file_info(file); - if (info && info->get_file_type() != Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || !options.fbShowHidden)) { - size_t lastdot = info->get_name().find_last_of ('.'); - if (options.is_extention_enabled(lastdot!=Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){ - previewLoader->add (selectedDirectoryId,file->get_parse_name(),this); - previewsToLoad++; - } - } -} - -void FileCatalog::addAndOpenFile (const Glib::ustring& fname) { - - Glib::RefPtr file = Gio::File::create_for_path (fname); - if (!file ) - return; - if( !file->query_exists()) - return; - Glib::RefPtr info = safe_query_file_info(file); - if( !info ) - return; - size_t lastdot = info->get_name().find_last_of ('.'); - if (options.is_extention_enabled(lastdot!=Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){ - // if supported, load thumbnail first - Thumbnail* tmb = cacheMgr->getEntry (file->get_parse_name()); - if (tmb) { - FileBrowserEntry* entry = new FileBrowserEntry (tmb, file->get_parse_name()); - previewReady (selectedDirectoryId,entry); - // open the file - FCOIParams* params = new FCOIParams; - params->catalog = this; - params->tmb.push_back (tmb); - tmb->increaseRef (); - g_idle_add (openRequestedUI, params); - } - } -} - -void FileCatalog::emptyTrash () { - - const std::vector t = fileBrowser->getEntries (); - std::vector toDel; - for (size_t i=0; i(t[i]))->thumbnail->getStage()==1) - toDel.push_back (static_cast(t[i])); - deleteRequested (toDel, false); - trashChanged(); -} - -bool FileCatalog::trashIsEmpty () { - const std::vector t = fileBrowser->getEntries (); - for (size_t i=0; i(t[i]))->thumbnail->getStage()==1) - return false; - - return true; -} - -void FileCatalog::zoomIn () { - - fileBrowser->zoomIn (); - refreshHeight(); - -} -void FileCatalog::zoomOut () { - - fileBrowser->zoomOut (); - refreshHeight(); - -} -void FileCatalog::refreshEditedState (const std::set& efiles) { - - editedFiles = efiles; - fileBrowser->refreshEditedState (efiles); -} - -void FileCatalog::selectionChanged (std::vector tbe) { - - if (fslistener) - fslistener->selectionChanged (tbe); -} - -// Called within GTK UI thread -void FileCatalog::exifFilterChanged () { - - currentEFS = filterPanel->getFilter (); - hasValidCurrentEFS = true; - fileBrowser->applyFilter (getFilter ()); - _refreshProgressBar(); -} - -void FileCatalog::setFilterPanel (FilterPanel* fpanel) { - - filterPanel = fpanel; - filterPanel->set_sensitive (false); - filterPanel->setFilterPanelListener (this); -} -void FileCatalog::trashChanged () { - if (trashIsEmpty()) { - bTrash->set_image(*iTrashEmpty); - } - else { - bTrash->set_image(*iTrashFull); - } -} - -// Called within GTK UI thread -void FileCatalog::buttonQueryClearPressed () { - Query->set_text(""); - FileCatalog::executeQuery (); -} - -// Called within GTK UI thread -void FileCatalog::executeQuery(){ - // if BrowsePath text was changed, do a full browse; - // otherwise filter only - - if (BrowsePath->get_text()!=selectedDirectory) - buttonBrowsePathPressed (); - else - FileCatalog::filterChanged (); -} - -bool FileCatalog::Query_key_pressed (GdkEventKey *event){ - - bool shift = event->state & GDK_SHIFT_MASK; - - switch (event->keyval) { - case GDK_Escape: - // Clear Query if the Escape character is pressed within it - if (!shift){ - FileCatalog::buttonQueryClearPressed (); - return true; - } - break; - default: - break; - } - return false; -} - -void FileCatalog::updateFBQueryTB (bool singleRow) { - hbToolBar1->reference(); - if (singleRow) { - bool removed = removeIfThere(this, hbToolBar1, false); - if (removed) { - buttonBar->pack_start(*hbToolBar1, Gtk::PACK_EXPAND_WIDGET, 0); - } - } - else { - bool removed = removeIfThere(buttonBar, hbToolBar1, false); - if (removed) { - pack_start(*hbToolBar1, Gtk::PACK_SHRINK, 0); - reorder_child(*hbToolBar1, 0); - } - } - hbToolBar1->unreference(); -} - -void FileCatalog::updateFBToolBarVisibility (bool showFilmStripToolBar){ - if (showFilmStripToolBar) - showToolBar(); - else - hideToolBar(); - refreshHeight(); -} - -void FileCatalog::buttonBrowsePathPressed () { - Glib::ustring BrowsePathValue = BrowsePath->get_text(); - Glib::ustring DecodedPathPrefix=""; - Glib::ustring FirstChar; - - // handle shortcuts in the BrowsePath -- START - // read the 1-st character from the path - FirstChar = BrowsePathValue.substr (0,1); - - if (FirstChar=="~"){ // home directory - DecodedPathPrefix = Glib::get_home_dir(); - } - else if (FirstChar=="!"){ // user's pictures directory - //DecodedPathPrefix = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES); - DecodedPathPrefix = safe_get_user_picture_dir(); - } - - if (!DecodedPathPrefix.empty()){ - BrowsePathValue = Glib::ustring::compose ("%1%2",DecodedPathPrefix,BrowsePathValue.substr (1,BrowsePath->get_text_length()-1)); - BrowsePath->set_text(BrowsePathValue); - } - // handle shortcuts in the BrowsePath -- END - - // validate the path - if (safe_file_test(BrowsePathValue, Glib::FILE_TEST_IS_DIR) && dirlistener){ - dirlistener->selectDir (BrowsePathValue); - } - else - // error, likely path not found: show red arrow - buttonBrowsePath->set_image (*iRefreshRed); -} - -bool FileCatalog::BrowsePath_key_pressed (GdkEventKey *event){ - - bool shift = event->state & GDK_SHIFT_MASK; - - switch (event->keyval) { - case GDK_Escape: - // On Escape character Reset BrowsePath to selectedDirectory - if (!shift){ - BrowsePath->set_text(selectedDirectory); - // place cursor at the end - BrowsePath->select_region(BrowsePath->get_text_length(), BrowsePath->get_text_length()); - return true; - } - break; - default: - break; - } - return false; -} - -void FileCatalog::tbLeftPanel_1_visible (bool visible){ - if (visible) - tbLeftPanel_1->show(); - else - tbLeftPanel_1->hide(); -} -void FileCatalog::tbRightPanel_1_visible (bool visible){ - if (visible) - tbRightPanel_1->show(); - else - tbRightPanel_1->hide(); -} -void FileCatalog::tbLeftPanel_1_toggled () { - removeIfThere (filepanel->dirpaned, filepanel->placespaned, false); - if (tbLeftPanel_1->get_active()){ - filepanel->dirpaned->pack1 (*filepanel->placespaned, false, true); - tbLeftPanel_1->set_image (*iLeftPanel_1_Hide); - options.browserDirPanelOpened = true; - } - else { - tbLeftPanel_1->set_image (*iLeftPanel_1_Show); - options.browserDirPanelOpened = false; - } -} - -void FileCatalog::tbRightPanel_1_toggled () { - if (tbRightPanel_1->get_active()){ - filepanel->rightBox->show(); - tbRightPanel_1->set_image (*iRightPanel_1_Hide); - options.browserToolPanelOpened = true; - } - else{ - filepanel->rightBox->hide(); - tbRightPanel_1->set_image (*iRightPanel_1_Show); - options.browserToolPanelOpened = false; - } -} - -bool FileCatalog::CheckSidePanelsVisibility(){ - if(tbLeftPanel_1->get_active()==false && tbRightPanel_1->get_active()==false) - return false; - else - return true; -} -void FileCatalog::toggleSidePanels(){ - // toggle left AND right panels - - bool bAllSidePanelsVisible; - bAllSidePanelsVisible= CheckSidePanelsVisibility(); - - tbLeftPanel_1->set_active (!bAllSidePanelsVisible); - tbRightPanel_1->set_active (!bAllSidePanelsVisible); -} - -void FileCatalog::toggleLeftPanel() { - tbLeftPanel_1->set_active (!tbLeftPanel_1->get_active()); -} - -void FileCatalog::toggleRightPanel() { - tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); -} - - -void FileCatalog::selectImage (Glib::ustring fname, bool clearFilters) { - - Glib::ustring dirname = Glib::path_get_dirname(fname); - if (!dirname.empty()){ - BrowsePath->set_text(dirname); - - - if (clearFilters){ // clear all filters - Query->set_text(""); - categoryButtonToggled(bFilterClear,false); - // disable exif filters - if (filterPanel->isEnabled()) filterPanel->setEnabled (false); - } - - if (BrowsePath->get_text()!=selectedDirectory){ - // reload or refresh thumbs and select image - buttonBrowsePathPressed (); - // the actual selection of image will be handled asynchronously at the end of FileCatalog::previewsFinishedUI - imageToSelect_fname = fname; - } - else{ - // FileCatalog::filterChanged ();//this will be replaced by queue_draw() in fileBrowser->selectImage - fileBrowser->selectImage(fname); - imageToSelect_fname = ""; - } - } -} - - -void FileCatalog::openNextPreviousEditorImage (Glib::ustring fname, bool clearFilters, eRTNav nextPrevious) { - - Glib::ustring dirname = Glib::path_get_dirname(fname); - if (!dirname.empty()){ - BrowsePath->set_text(dirname); - - - if (clearFilters){ // clear all filters - Query->set_text(""); - categoryButtonToggled(bFilterClear,false); - // disable exif filters - if (filterPanel->isEnabled()) filterPanel->setEnabled (false); - } - - if (BrowsePath->get_text()!=selectedDirectory){ - // reload or refresh thumbs and select image - buttonBrowsePathPressed (); - // the actual selection of image will be handled asynchronously at the end of FileCatalog::previewsFinishedUI - refImageForOpen_fname = fname; - actionNextPrevious = nextPrevious; - } - else{ - // FileCatalog::filterChanged ();//this was replace by queue_draw() in fileBrowser->selectImage - fileBrowser->openNextPreviousEditorImage(fname,nextPrevious); - refImageForOpen_fname = ""; - actionNextPrevious = NAV_NONE; - } - } -} - -bool FileCatalog::handleShortcutKey (GdkEventKey* event) { - - bool ctrl = event->state & GDK_CONTROL_MASK; - bool shift = event->state & GDK_SHIFT_MASK; - bool alt = event->state & GDK_MOD1_MASK; -#ifdef __WIN32__ - bool altgr = event->state & GDK_MOD2_MASK; -#else - bool altgr = event->state & GDK_MOD5_MASK; -#endif - modifierKey = event->state; - - // GUI Layout - switch(event->keyval) { - case GDK_l: - if (!alt)tbLeftPanel_1->set_active (!tbLeftPanel_1->get_active()); // toggle left panel - if (alt && !ctrl) tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); // toggle right panel - if (alt && ctrl) { - tbLeftPanel_1->set_active (!tbLeftPanel_1->get_active()); // toggle left panel - tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); // toggle right panel - } - return true; - case GDK_m: - if (!ctrl && !alt) toggleSidePanels(); - return true; - } - - if (shift){ - switch(event->keyval) { - case GDK_Escape: - BrowsePath->set_text(selectedDirectory); - // set focus on something neutral, this is useful to remove focus from BrowsePath and Query - // when need to execute a shortcut, which otherwise will be typed into those fields - filepanel->grab_focus(); - return true; - } - } - -#ifdef __WIN32__ - if (!alt && !shift && !altgr) { // shift is reserved for ranking - switch(event->hardware_keycode) { - case 0x30: - categoryButtonToggled(bUnRanked,false); - return true; - case 0x31: - categoryButtonToggled(bRank[0],false); - return true; - case 0x32: - categoryButtonToggled(bRank[1],false); - return true; - case 0x33: - categoryButtonToggled(bRank[2],false); - return true; - case 0x34: - categoryButtonToggled(bRank[3],false); - return true; - case 0x35: - categoryButtonToggled(bRank[4],false); - return true; - case 0x36: - categoryButtonToggled(bEdited[0],false); - return true; - case 0x37: - categoryButtonToggled(bEdited[1],false); - return true; - } - } - if (!alt && !shift) { - switch(event->keyval) { - - case GDK_Return: - case GDK_KP_Enter: - if (BrowsePath->is_focus()){ - FileCatalog::buttonBrowsePathPressed (); - return true; - } - break; - } - } - - if (alt && !shift) { // shift is reserved for color labeling - switch(event->hardware_keycode) { - case 0x30: - categoryButtonToggled(bUnCLabeled,false); - return true; - case 0x31: - categoryButtonToggled(bCLabel[0],false); - return true; - case 0x32: - categoryButtonToggled(bCLabel[1],false); - return true; - case 0x33: - categoryButtonToggled(bCLabel[2],false); - return true; - case 0x34: - categoryButtonToggled(bCLabel[3],false); - return true; - case 0x35: - categoryButtonToggled(bCLabel[4],false); - return true; - case 0x36: - categoryButtonToggled(bRecentlySaved[0],false); - return true; - case 0x37: - categoryButtonToggled(bRecentlySaved[1],false); - return true; - } - } -#else - if (!alt && !shift && !altgr) { // shift is reserved for ranking - switch(event->hardware_keycode) { - case 0x13: - categoryButtonToggled(bUnRanked,false); - return true; - case 0x0a: - categoryButtonToggled(bRank[0],false); - return true; - case 0x0b: - categoryButtonToggled(bRank[1],false); - return true; - case 0x0c: - categoryButtonToggled(bRank[2],false); - return true; - case 0x0d: - categoryButtonToggled(bRank[3],false); - return true; - case 0x0e: - categoryButtonToggled(bRank[4],false); - return true; - case 0x0f: - categoryButtonToggled(bEdited[0],false); - return true; - case 0x10: - categoryButtonToggled(bEdited[1],false); - return true; - } - } - if (!alt && !shift) { - switch(event->keyval) { - - case GDK_Return: - case GDK_KP_Enter: - if (BrowsePath->is_focus()){ - FileCatalog::buttonBrowsePathPressed (); - return true; - } - break; - } - } - - if (alt && !shift) { // shift is reserved for color labeling - switch(event->hardware_keycode) { - case 0x13: - categoryButtonToggled(bUnCLabeled,false); - return true; - case 0x0a: - categoryButtonToggled(bCLabel[0],false); - return true; - case 0x0b: - categoryButtonToggled(bCLabel[1],false); - return true; - case 0x0c: - categoryButtonToggled(bCLabel[2],false); - return true; - case 0x0d: - categoryButtonToggled(bCLabel[3],false); - return true; - case 0x0e: - categoryButtonToggled(bCLabel[4],false); - return true; - case 0x0f: - categoryButtonToggled(bRecentlySaved[0],false); - return true; - case 0x10: - categoryButtonToggled(bRecentlySaved[1],false); - return true; - } - } -#endif - if (!ctrl && !alt) { - switch(event->keyval) { - case GDK_d: - case GDK_D: - categoryButtonToggled(bFilterClear,false); - return true; - } - } - - if (!ctrl || (alt && !options.tabbedUI)) { - switch(event->keyval) { - - case GDK_bracketright: - coarsePanel->rotateRight(); - return true; - case GDK_bracketleft: - coarsePanel->rotateLeft(); - return true; - case GDK_i: - case GDK_I: - exifInfo->set_active (!exifInfo->get_active()); - return true; - - case GDK_plus: - case GDK_equal: - zoomIn(); - return true; - case GDK_minus: - case GDK_underscore: - zoomOut(); - return true; - } - } - if (ctrl && !alt) { - switch (event->keyval) { - case GDK_o: - BrowsePath->select_region(0, BrowsePath->get_text_length()); - BrowsePath->grab_focus(); - return true; - case GDK_f: - Query->select_region(0, Query->get_text_length()); - Query->grab_focus(); - return true; - case GDK_t: - case GDK_T: - modifierKey = 0; // HOMBRE: yet another hack.... otherwise the shortcut won't work - categoryButtonToggled(bTrash,false); - return true; - } - } - if (!ctrl && !alt && shift) { - switch (event->keyval) { - case GDK_t: - case GDK_T: - if (inTabMode) { - if (options.showFilmStripToolBar) - hideToolBar(); - else - showToolBar(); - options.showFilmStripToolBar = !options.showFilmStripToolBar; - } - return true; - } - } - if (!ctrl && !alt && !shift) { - switch (event->keyval) { - case GDK_t: - case GDK_T: - if (inTabMode) { - if (options.showFilmStripToolBar) - hideToolBar(); - else - showToolBar(); - options.showFilmStripToolBar = !options.showFilmStripToolBar; - } - refreshHeight(); - return true; - } - } - - if (fileBrowser->keyPressed(event)) - return true; - - return false; -} - -void FileCatalog::showToolBar() { - if (!options.FileBrowserToolbarSingleRow) - hbToolBar1->show(); - buttonBar->show(); -} - -void FileCatalog::hideToolBar() { - if (!options.FileBrowserToolbarSingleRow) - hbToolBar1->hide(); - buttonBar->hide(); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2011 Michael Ezra + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include +#include +#include +#include "../rtengine/rt_math.h" + +#include "filecatalog.h" +#include "filepanel.h" +#include "options.h" +#include "cachemanager.h" +#include "multilangmgr.h" +#include "guiutils.h" +#include "renamedlg.h" +#include "thumbimageupdater.h" +#include "../rtengine/safegtk.h" +#include "batchqueue.h" +#include "rtimage.h" + +using namespace std; + +#define CHECKTIME 2000 + +FileCatalog::FileCatalog (CoarsePanel* cp, ToolBar* tb, FilePanel* filepanel) : + filepanel(filepanel), + selectedDirectoryId(1), + listener(NULL), + fslistener(NULL), + dirlistener(NULL), + hasValidCurrentEFS(false), + filterPanel(NULL), + previewsToLoad(0), + previewsLoaded(0), + coarsePanel(cp), + toolBar(tb) + { + + inTabMode=false; + + // construct and initialize thumbnail browsers + fileBrowser = Gtk::manage( new FileBrowser() ); + fileBrowser->setFileBrowserListener (this); + fileBrowser->setArrangement (ThumbBrowserBase::TB_Vertical); + fileBrowser->show (); + + set_size_request(0,250); + // construct trash panel with the extra "empty trash" button + trashButtonBox = Gtk::manage( new Gtk::VBox ); + Gtk::Button* emptyT = Gtk::manage( new Gtk::Button (M("FILEBROWSER_EMPTYTRASH"))); + emptyT->set_tooltip_markup (M("FILEBROWSER_EMPTYTRASHHINT")); + emptyT->set_image (*Gtk::manage(new RTImage ("trash.png"))); + emptyT->signal_pressed().connect (sigc::mem_fun(*this, &FileCatalog::emptyTrash)); + trashButtonBox->pack_start (*emptyT, Gtk::PACK_SHRINK, 4); + emptyT->show (); + trashButtonBox->show (); + + //initialize hbToolBar1 + hbToolBar1 = Gtk::manage(new Gtk::HBox ()); + + //setup BrowsePath + iRefreshWhite = new RTImage("refresh-white.png"); + iRefreshRed = new RTImage("refresh-red.png"); + + BrowsePath = Gtk::manage(new Gtk::Entry ()); + BrowsePath->set_width_chars (50); + BrowsePath->set_tooltip_markup (M("FILEBROWSER_BROWSEPATHHINT")); + Gtk::HBox* hbBrowsePath = Gtk::manage(new Gtk::HBox ()); + buttonBrowsePath = Gtk::manage(new Gtk::Button ()); + buttonBrowsePath->set_image (*iRefreshWhite); + buttonBrowsePath->set_tooltip_markup (M("FILEBROWSER_BROWSEPATHBUTTONHINT")); + buttonBrowsePath->set_relief (Gtk::RELIEF_NONE); + buttonBrowsePath->signal_clicked().connect( sigc::mem_fun(*this, &FileCatalog::buttonBrowsePathPressed) ); + hbBrowsePath->pack_start (*BrowsePath, Gtk::PACK_EXPAND_WIDGET,0); + hbBrowsePath->pack_start (*buttonBrowsePath,Gtk::PACK_SHRINK, 0); + hbToolBar1->pack_start (*hbBrowsePath, Gtk::PACK_EXPAND_WIDGET,0); + + BrowsePath->signal_activate().connect (sigc::mem_fun(*this, &FileCatalog::buttonBrowsePathPressed)); //respond to the Enter key + BrowsePath->signal_key_press_event().connect(sigc::mem_fun(*this, &FileCatalog::BrowsePath_key_pressed)); + + //setup Query + iQueryClear = new RTImage("gtk-close-small.png"); + Gtk::Label* labelQuery = Gtk::manage(new Gtk::Label(M("FILEBROWSER_QUERYLABEL"))); + Query = Gtk::manage(new Gtk::Entry ()); // cannot use Gtk::manage here as FileCatalog::getFilter will fail on Query->get_text() + Query->set_text(""); + Query->set_width_chars (20); // TODO !!! add this value to options? + Query->set_tooltip_markup (M("FILEBROWSER_QUERYHINT")); + Gtk::HBox* hbQuery = Gtk::manage(new Gtk::HBox ()); + buttonQueryClear = Gtk::manage(new Gtk::Button ()); + buttonQueryClear->set_image (*iQueryClear); + buttonQueryClear->set_tooltip_markup (M("FILEBROWSER_QUERYBUTTONHINT")); + buttonQueryClear->set_relief (Gtk::RELIEF_NONE); + buttonQueryClear->signal_clicked().connect( sigc::mem_fun(*this, &FileCatalog::buttonQueryClearPressed) ); + hbQuery->pack_start (*labelQuery,Gtk::PACK_SHRINK, 0); + hbQuery->pack_start (*Query,Gtk::PACK_SHRINK, 0); + hbQuery->pack_start (*buttonQueryClear,Gtk::PACK_SHRINK, 0); + hbToolBar1->pack_start (*hbQuery, Gtk::PACK_SHRINK,0); + + Query->signal_activate().connect (sigc::mem_fun(*this, &FileCatalog::executeQuery)); //respond to the Enter key + Query->signal_key_press_event().connect(sigc::mem_fun(*this, &FileCatalog::Query_key_pressed)); + + // if NOT a single row toolbar + if (!options.FileBrowserToolbarSingleRow) pack_start (*hbToolBar1, Gtk::PACK_SHRINK,0); + + // setup button bar + buttonBar = Gtk::manage( new Gtk::HBox () ); + pack_start (*buttonBar, Gtk::PACK_SHRINK); + + buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); + + tbLeftPanel_1 = new Gtk::ToggleButton (); + iLeftPanel_1_Show = new RTImage("panel-to-right.png"); + iLeftPanel_1_Hide = new RTImage("panel-to-left.png"); + + tbLeftPanel_1->set_relief(Gtk::RELIEF_NONE); + tbLeftPanel_1->set_active (true); + tbLeftPanel_1->set_tooltip_markup (M("MAIN_TOOLTIP_SHOWHIDELP1")); + tbLeftPanel_1->set_image (*iLeftPanel_1_Hide); + tbLeftPanel_1->signal_toggled().connect( sigc::mem_fun(*this, &FileCatalog::tbLeftPanel_1_toggled) ); + buttonBar->pack_start (*tbLeftPanel_1, Gtk::PACK_SHRINK); + + buttonBar->pack_start (*(new Gtk::VSeparator), Gtk::PACK_SHRINK); + + + iFilterClear = new RTImage ("filterclear.png"); + igFilterClear = new RTImage ("filter.png"); + bFilterClear = Gtk::manage(new Gtk::ToggleButton ()); + bFilterClear->set_active (true); + bFilterClear->set_image(*iFilterClear);// (*Gtk::manage(new RTImage ("filterclear.png"))); + bFilterClear->set_relief (Gtk::RELIEF_NONE); + bFilterClear->set_tooltip_markup (M("FILEBROWSER_SHOWDIRHINT")); + bFilterClear->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); + bCateg[0] = bFilterClear->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bFilterClear, true)); + buttonBar->pack_start (*bFilterClear, Gtk::PACK_SHRINK); + buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); + + fltrVbox1 = Gtk::manage (new Gtk::VBox()); + fltrRankbox = Gtk::manage (new Gtk::HBox()); + fltrLabelbox = Gtk::manage (new Gtk::HBox()); + + iUnRanked = new RTImage ("ratednot.png"); + igUnRanked = new RTImage ("ratednotg.png"); + bUnRanked = Gtk::manage( new Gtk::ToggleButton () ); + bUnRanked->set_active (false); + bUnRanked->set_image (*igUnRanked); + bUnRanked->set_relief (Gtk::RELIEF_NONE); + bUnRanked->set_tooltip_markup (M("FILEBROWSER_SHOWUNRANKHINT")); + bCateg[1] = bUnRanked->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bUnRanked, true)); + fltrRankbox->pack_start (*bUnRanked, Gtk::PACK_SHRINK); + bUnRanked->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); + + for (int i=0; i<5; i++) { + iranked[i] = new RTImage ("rated.png"); + igranked[i] = new RTImage ("grayrated.png"); + iranked[i]->show (); + igranked[i]->show (); + bRank[i] = Gtk::manage( new Gtk::ToggleButton () ); + bRank[i]->set_image (*igranked[i]); + bRank[i]->set_relief (Gtk::RELIEF_NONE); + fltrRankbox->pack_start (*bRank[i], Gtk::PACK_SHRINK); + bCateg[i+2] = bRank[i]->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bRank[i], true)); + bRank[i]->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); + } + + iUnCLabeled = new RTImage ("clabel0.png"); + igUnCLabeled = new RTImage ("cglabel0.png"); + bUnCLabeled = Gtk::manage(new Gtk::ToggleButton ()); + bUnCLabeled->set_active (false); + bUnCLabeled->set_image (*igUnCLabeled); + bUnCLabeled->set_relief (Gtk::RELIEF_NONE); + bUnCLabeled->set_tooltip_markup (M("FILEBROWSER_SHOWUNCOLORHINT")); + bCateg[7] = bUnCLabeled->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bUnCLabeled, true)); + fltrLabelbox->pack_start (*bUnCLabeled, Gtk::PACK_SHRINK); + bUnCLabeled->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); + + for (int i=0; i<5; i++) { + iCLabeled[i] = new RTImage (Glib::ustring::compose("%1%2%3","clabel",i+1,".png")); + igCLabeled[i] = new RTImage (Glib::ustring::compose("%1%2%3","cglabel",i+1,".png")); + iCLabeled[i]->show (); + igCLabeled[i]->show (); + bCLabel[i] = Gtk::manage(new Gtk::ToggleButton ()); + bCLabel[i]->set_image (*igCLabeled[i]); + bCLabel[i]->set_relief (Gtk::RELIEF_NONE); + fltrLabelbox->pack_start (*bCLabel[i], Gtk::PACK_SHRINK); + bCateg[i+8] = bCLabel[i]->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bCLabel[i], true)); + bCLabel[i]->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); + } + + fltrVbox1->pack_start (*fltrRankbox, Gtk::PACK_SHRINK,0); + fltrVbox1->pack_start (*fltrLabelbox, Gtk::PACK_SHRINK,0); + buttonBar->pack_start (*fltrVbox1, Gtk::PACK_SHRINK); + + bRank[0]->set_tooltip_markup (M("FILEBROWSER_SHOWRANK1HINT")); + bRank[1]->set_tooltip_markup (M("FILEBROWSER_SHOWRANK2HINT")); + bRank[2]->set_tooltip_markup (M("FILEBROWSER_SHOWRANK3HINT")); + bRank[3]->set_tooltip_markup (M("FILEBROWSER_SHOWRANK4HINT")); + bRank[4]->set_tooltip_markup (M("FILEBROWSER_SHOWRANK5HINT")); + + bCLabel[0]->set_tooltip_markup (M("FILEBROWSER_SHOWCOLORLABEL1HINT")); + bCLabel[1]->set_tooltip_markup (M("FILEBROWSER_SHOWCOLORLABEL2HINT")); + bCLabel[2]->set_tooltip_markup (M("FILEBROWSER_SHOWCOLORLABEL3HINT")); + bCLabel[3]->set_tooltip_markup (M("FILEBROWSER_SHOWCOLORLABEL4HINT")); + bCLabel[4]->set_tooltip_markup (M("FILEBROWSER_SHOWCOLORLABEL5HINT")); + + buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); + + fltrVbox2 = Gtk::manage (new Gtk::VBox()); + fltrEditedBox = Gtk::manage (new Gtk::HBox()); + fltrRecentlySavedBox = Gtk::manage (new Gtk::HBox()); + + // bEdited + iEdited[0] = new RTImage ("editednot-small.png"); + igEdited[0] = new RTImage ("editednotg-small.png"); + iEdited[1] = new RTImage ("edited-small.png"); + igEdited[1] = new RTImage ("editedg-small.png"); + for (int i=0; i<2; i++) { + iEdited[i]->show (); + bEdited[i] = Gtk::manage(new Gtk::ToggleButton ()); + bEdited[i]->set_active (false); + bEdited[i]->set_image (*igEdited[i]); + bEdited[i]->set_relief (Gtk::RELIEF_NONE); + fltrEditedBox->pack_start (*bEdited[i], Gtk::PACK_SHRINK); + //13, 14 + bCateg[i+13] = bEdited[i]->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bEdited[i], true)); + bEdited[i]->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); + } + bEdited[0]->set_tooltip_markup (M("FILEBROWSER_SHOWEDITEDNOTHINT")); + bEdited[1]->set_tooltip_markup (M("FILEBROWSER_SHOWEDITEDHINT")); + + // RecentlySaved + iRecentlySaved[0] = new RTImage ("savednot.png"); + igRecentlySaved[0] = new RTImage ("savednotg.png"); + iRecentlySaved[1] = new RTImage ("saved.png"); + igRecentlySaved[1] = new RTImage ("savedg.png"); + for (int i=0; i<2; i++) { + iRecentlySaved[i]->show (); + bRecentlySaved[i] = Gtk::manage(new Gtk::ToggleButton ()); + bRecentlySaved[i]->set_active (false); + bRecentlySaved[i]->set_image (*igRecentlySaved[i]); + bRecentlySaved[i]->set_relief (Gtk::RELIEF_NONE); + fltrRecentlySavedBox->pack_start (*bRecentlySaved[i], Gtk::PACK_SHRINK); + //15, 16 + bCateg[i+15] = bRecentlySaved[i]->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bRecentlySaved[i], true)); + bRecentlySaved[i]->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); + } + bRecentlySaved[0]->set_tooltip_markup (M("FILEBROWSER_SHOWRECENTLYSAVEDNOTHINT")); + bRecentlySaved[1]->set_tooltip_markup (M("FILEBROWSER_SHOWRECENTLYSAVEDHINT")); + + fltrVbox2->pack_start (*fltrEditedBox, Gtk::PACK_SHRINK,0); + fltrVbox2->pack_start (*fltrRecentlySavedBox, Gtk::PACK_SHRINK,0); + buttonBar->pack_start (*fltrVbox2, Gtk::PACK_SHRINK); + + buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); + + // Trash + iTrashEmpty = new RTImage("trash-show-empty.png") ; + iTrashFull = new RTImage("trash-show-full.png") ; + + bTrash = Gtk::manage( new Gtk::ToggleButton () ); + bTrash->set_image (*iTrashEmpty); + bTrash->set_relief (Gtk::RELIEF_NONE); + bTrash->set_tooltip_markup (M("FILEBROWSER_SHOWTRASHHINT")); + bCateg[17] = bTrash->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bTrash, true)); + bTrash->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); + + iNotTrash = new RTImage("trash-hide-deleted.png") ; + + bNotTrash = Gtk::manage( new Gtk::ToggleButton () ); + bNotTrash->set_image (*iNotTrash); + bNotTrash->set_relief (Gtk::RELIEF_NONE); + bNotTrash->set_tooltip_markup (M("FILEBROWSER_SHOWNOTTRASHHINT")); + bCateg[18] = bNotTrash->signal_toggled().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::categoryButtonToggled), bNotTrash, true)); + bNotTrash->signal_button_press_event().connect (sigc::mem_fun(*this, &FileCatalog::capture_event),false); + + buttonBar->pack_start (*bTrash, Gtk::PACK_SHRINK); + buttonBar->pack_start (*bNotTrash, Gtk::PACK_SHRINK); + buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); + fileBrowser->trash_changed().connect( sigc::mem_fun(*this, &FileCatalog::trashChanged) ); + + // 0 - bFilterClear + // 1 - bUnRanked + // 2 - bRank[0] + // 3 - bRank[1] + // 4 - bRank[2] + // 5 - bRank[3] + // 6 - bRank[4] + // 7 - bUnCLabeled + // 8 - bCLabel[0] + // 9 - bCLabel[1] + // 10 - bCLabel[2] + // 11 - bCLabel[3] + // 12 - bCLabel[4] + // 13 - bEdited[0] + // 14 - bEdited[1] + // 15 - bRecentlySaved[0] + // 16 - bRecentlySaved[1] + // 17 - bTrash + // 18 - bNotTrash + + categoryButtons[0] = bFilterClear; + categoryButtons[1] = bUnRanked; + for (int i=0; i<5; i++){ categoryButtons[i+2] = bRank[i];} + categoryButtons[7] = bUnCLabeled; + for (int i=0; i<5; i++){ categoryButtons[i+8] = bCLabel[i];} + for (int i=0; i<2; i++){ categoryButtons[i+13] = bEdited[i];} + for (int i=0; i<2; i++){ categoryButtons[i+15] = bRecentlySaved[i];} + categoryButtons[17] = bTrash; + categoryButtons[18] = bNotTrash; + + exifInfo = Gtk::manage(new Gtk::ToggleButton ()); + exifInfo->set_image (*Gtk::manage(new RTImage ("info.png"))); + exifInfo->set_relief (Gtk::RELIEF_NONE); + exifInfo->set_tooltip_markup (M("FILEBROWSER_SHOWEXIFINFO")); + exifInfo->set_active( options.showFileNames ); + exifInfo->signal_toggled().connect(sigc::mem_fun(*this, &FileCatalog::exifInfoButtonToggled)); + buttonBar->pack_start (*exifInfo, Gtk::PACK_SHRINK); + + // thumbnail zoom + Gtk::HBox* zoomBox = Gtk::manage( new Gtk::HBox () ); + zoomInButton = Gtk::manage( new Gtk::Button () ); + zoomInButton->set_image (*Gtk::manage(new RTImage ("gtk-zoom-in.png"))); + zoomInButton->signal_pressed().connect (sigc::mem_fun(*this, &FileCatalog::zoomIn)); + zoomInButton->set_relief (Gtk::RELIEF_NONE); + zoomInButton->set_tooltip_markup (M("FILEBROWSER_ZOOMINHINT")); + zoomBox->pack_end (*zoomInButton, Gtk::PACK_SHRINK); + zoomOutButton = Gtk::manage( new Gtk::Button () ); + zoomOutButton->set_image (*Gtk::manage(new RTImage ("gtk-zoom-out.png"))); + zoomOutButton->signal_pressed().connect (sigc::mem_fun(*this, &FileCatalog::zoomOut)); + zoomOutButton->set_relief (Gtk::RELIEF_NONE); + zoomOutButton->set_tooltip_markup (M("FILEBROWSER_ZOOMOUTHINT")); + zoomBox->pack_end (*zoomOutButton, Gtk::PACK_SHRINK); + + buttonBar->pack_start (*zoomBox, Gtk::PACK_SHRINK); + buttonBar->pack_start (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK); + + //iRightArrow = new RTImage("right.png"); + //iRightArrow_red = new RTImage("right_red.png"); + + // if it IS a single row toolbar + if (options.FileBrowserToolbarSingleRow) buttonBar->pack_start (*hbToolBar1, Gtk::PACK_EXPAND_WIDGET,0); + + tbRightPanel_1 = new Gtk::ToggleButton (); + iRightPanel_1_Show = new RTImage("panel-to-left.png"); + iRightPanel_1_Hide = new RTImage("panel-to-right.png"); + + tbRightPanel_1->set_relief(Gtk::RELIEF_NONE); + tbRightPanel_1->set_active (true); + tbRightPanel_1->set_tooltip_markup (M("MAIN_TOOLTIP_SHOWHIDERP1")); + tbRightPanel_1->set_image (*iRightPanel_1_Hide); + tbRightPanel_1->signal_toggled().connect( sigc::mem_fun(*this, &FileCatalog::tbRightPanel_1_toggled) ); + buttonBar->pack_end (*tbRightPanel_1, Gtk::PACK_SHRINK); + + buttonBar->pack_end (*coarsePanel, Gtk::PACK_SHRINK); + buttonBar->pack_end (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK, 4); + buttonBar->pack_end (*toolBar, Gtk::PACK_SHRINK); + buttonBar->pack_end (*Gtk::manage(new Gtk::VSeparator), Gtk::PACK_SHRINK, 4); + + // add default panel + hBox = Gtk::manage( new Gtk::HBox () ); + hBox->show (); + hBox->pack_end (*fileBrowser); + fileBrowser->applyFilter (getFilter()); // warning: can call this only after all objects used in getFilter (e.g. Query) are instantiated + //printf("FileCatalog::FileCatalog fileBrowser->applyFilter (getFilter())\n"); + pack_start (*hBox); + + enabled = true; + + lastScrollPos = 0; + for (int i=0; i<18; i++) { + hScrollPos[i] = 0; + vScrollPos[i] = 0; + } + + selectedDirectory = ""; +#ifdef WIN32 + wdMonitor = NULL; +#endif +} + +FileCatalog::~FileCatalog(){ + for (int i=0; i<5; i++) { + delete iranked[i]; + delete igranked[i]; + delete iCLabeled[i]; + delete igCLabeled[i]; + } + for (int i=0; i<2; i++) { + delete iEdited[i]; + delete igEdited[i]; + delete iRecentlySaved[i]; + delete igRecentlySaved[i]; + } + delete iFilterClear; + delete igFilterClear; + delete iUnRanked; + delete igUnRanked; + delete iUnCLabeled; + delete igUnCLabeled; + delete iTrashEmpty; + delete iTrashFull; + delete iRefreshWhite; + delete iRefreshRed; + delete iQueryClear; + delete iLeftPanel_1_Show; + delete iLeftPanel_1_Hide; + delete iRightPanel_1_Show; + delete iRightPanel_1_Hide; +} + +bool FileCatalog::capture_event(GdkEventButton* event){ + // need to record modifiers on the button press, because signal_toggled does not pass the event. + modifierKey = event->state; + return false; +} + +void FileCatalog::exifInfoButtonToggled() +{ + if (inTabMode) + options.filmStripShowFileNames = exifInfo->get_active(); + else + options.showFileNames = exifInfo->get_active(); + fileBrowser->refreshThumbImages (); +} + +void FileCatalog::on_realize() { + + Gtk::VBox::on_realize(); + Pango::FontDescription fontd = get_pango_context()->get_font_description (); + fileBrowser->get_pango_context()->set_font_description (fontd); +// batchQueue->get_pango_context()->set_font_description (fontd); +} + +void FileCatalog::closeDir () { + + if (filterPanel) + filterPanel->set_sensitive (false); + + if (exportPanel) + exportPanel->set_sensitive (false); + +#ifndef WIN32 + if (dirMonitor) + dirMonitor->cancel (); +#else + if (wdMonitor) { + delete wdMonitor; + wdMonitor = NULL; + } +#endif + + // ignore old requests + ++selectedDirectoryId; + + // terminate thumbnail preview loading + previewLoader->removeAllJobs (); + + // terminate thumbnail updater + thumbImageUpdater->removeAllJobs (); + + // remove entries + selectedDirectory = ""; + fileBrowser->close (); + fileNameList.clear (); + + { + MyMutex::MyLock lock(dirEFSMutex); + dirEFS.clear (); + } + hasValidCurrentEFS = false; + redrawAll (); +} + +std::vector FileCatalog::getFileList () { + + std::vector names; + Glib::RefPtr dir = Gio::File::create_for_path (selectedDirectory); + safe_build_file_list (dir, names, selectedDirectory, &(options.parsedExtensions)); +// Issue 2406 std::sort (names.begin(), names.end()); + return names; +} + +void FileCatalog::dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile) { + + try { + Glib::RefPtr dir = Gio::File::create_for_path (dirname); + + if (!dir) + return; + closeDir (); + previewsToLoad = 0; + previewsLoaded = 0; + // if openfile exists, we have to open it first (it is a command line argument) + if (!openfile.empty()) + addAndOpenFile (openfile); + + selectedDirectory = dir->get_parse_name(); + //printf("FileCatalog::dirSelected selectedDirectory = %s\n",selectedDirectory.c_str()); + BrowsePath->set_text (selectedDirectory); + buttonBrowsePath->set_image (*iRefreshWhite); + fileNameList = getFileList (); + + for (unsigned int i=0; i f = Gio::File::create_for_path(fileNameList[i]); + if (f->get_parse_name() != openfile) // if we opened a file at the beginning don't add it again + checkAndAddFile (f); + } + + _refreshProgressBar (); + if (previewsToLoad == 0) { + filepanel->loadingThumbs(M("PROGRESSBAR_NOIMAGES"),0); + } else { + filepanel->loadingThumbs(M("PROGRESSBAR_LOADINGTHUMBS"),0); + } + +#ifdef WIN32 + wdMonitor = new WinDirMonitor (selectedDirectory, this); +#else + dirMonitor = dir->monitor_directory (); + dirMonitor->signal_changed().connect (sigc::bind(sigc::mem_fun(*this, &FileCatalog::on_dir_changed), false)); +#endif + } + catch (Glib::Exception& ex) { + std::cout << ex.what(); + } +} + +void FileCatalog::enableTabMode(bool enable) { + inTabMode = enable; + + if (enable) { + if (options.showFilmStripToolBar) + showToolBar(); + else + hideToolBar(); + exifInfo->set_active( options.filmStripShowFileNames ); + + } + else { + buttonBar->show(); + hbToolBar1->show(); + exifInfo->set_active( options.showFileNames ); + } + fileBrowser->enableTabMode(inTabMode); + + redrawAll(); +} + +void FileCatalog::_refreshProgressBar () { + // In tab mode, no progress bar at all + // Also mention that this progress bar only measures the FIRST pass (quick thumbnails) + // The second, usually longer pass is done multithreaded down in the single entries and is NOT measured by this + if (!inTabMode) { + GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected + + Gtk::Notebook *nb =(Gtk::Notebook *)(filepanel->get_parent()); + Gtk::Box* hbb=NULL; + Gtk::Label *label=NULL; + if( options.mainNBVertical ) + hbb = Gtk::manage (new Gtk::VBox ()); + else + hbb = Gtk::manage (new Gtk::HBox ()); + if (!previewsToLoad ) { + hbb->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU))); + int filteredCount = min(fileBrowser->getNumFiltered(),previewsLoaded); + + label = Gtk::manage (new Gtk::Label (M("MAIN_FRAME_FILEBROWSER")+ + (filteredCount!=previewsLoaded ? " ["+ Glib::ustring::format(filteredCount)+"/" : " (") + + Glib::ustring::format(previewsLoaded) + + (filteredCount!=previewsLoaded ? "]" : ")"))); + } else { + hbb->pack_start (*Gtk::manage (new Gtk::Image (Gtk::Stock::FIND, Gtk::ICON_SIZE_MENU))); + label = Gtk::manage (new Gtk::Label (M("MAIN_FRAME_FILEBROWSER")+" [" +Glib::ustring::format(std::fixed, std::setprecision(0), std::setw(3), (double)previewsLoaded / previewsToLoad*100 )+"%]" )); + filepanel->loadingThumbs("",(double)previewsLoaded / previewsToLoad); + } + if( options.mainNBVertical ) + label->set_angle(90); + hbb->pack_start (*label); + hbb->set_spacing (2); + hbb->set_tooltip_markup (M("MAIN_FRAME_FILEBROWSER_TOOLTIP")); + hbb->show_all (); + nb->set_tab_label(*filepanel,*hbb); + } +} + +int refreshProgressBarUI (void* data) { + (static_cast(data))->_refreshProgressBar (); + return 0; +} + +void FileCatalog::filterApplied() { + g_idle_add (refreshProgressBarUI, this); +} + + +void FileCatalog::previewReady (int dir_id, FileBrowserEntry* fdn) { + + if ( dir_id != selectedDirectoryId ) + return; + + // put it into the "full directory" browser + fdn->setImageAreaToolListener (iatlistener); + fileBrowser->addEntry (fdn); + + // update exif filter settings (minimal & maximal values of exif tags, cameras, lenses, etc...) + const CacheImageData* cfs = fdn->thumbnail->getCacheImageData(); + + { + MyMutex::MyLock lock(dirEFSMutex); + if (cfs->exifValid) { + if (cfs->fnumber < dirEFS.fnumberFrom) + dirEFS.fnumberFrom = cfs->fnumber; + if (cfs->fnumber > dirEFS.fnumberTo) + dirEFS.fnumberTo = cfs->fnumber; + if (cfs->shutter < dirEFS.shutterFrom) + dirEFS.shutterFrom = cfs->shutter; + if (cfs->shutter > dirEFS.shutterTo) + dirEFS.shutterTo = cfs->shutter; + if (cfs->iso>0 && (int)cfs->iso < dirEFS.isoFrom) + dirEFS.isoFrom = (int)cfs->iso; + if (cfs->iso>0 && (int)cfs->iso > dirEFS.isoTo) + dirEFS.isoTo = (int)cfs->iso; + if (cfs->focalLen < dirEFS.focalFrom) + dirEFS.focalFrom = cfs->focalLen; + if (cfs->focalLen > dirEFS.focalTo) + dirEFS.focalTo = cfs->focalLen; + } + dirEFS.filetypes.insert (cfs->filetype); + dirEFS.cameras.insert (cfs->getCamera()); + dirEFS.lenses.insert (cfs->lens); + dirEFS.expcomp.insert (cfs->expcomp); + } + + previewsLoaded++; + + g_idle_add (refreshProgressBarUI, this); +} + +int prevfinished (void* data) { + (static_cast(data))->previewsFinishedUI (); + return 0; +} + +// Called within GTK UI thread +void FileCatalog::previewsFinishedUI () { + + { + GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected + redrawAll (); + previewsToLoad = 0; + + if (filterPanel) { + filterPanel->set_sensitive (true); + if ( !hasValidCurrentEFS ){ + MyMutex::MyLock lock(dirEFSMutex); + currentEFS = dirEFS; + filterPanel->setFilter ( dirEFS,true ); + }else { + filterPanel->setFilter ( currentEFS,false ); + } + } + + if (exportPanel) + exportPanel->set_sensitive (true); + + // restart anything that might have been loaded low quality + fileBrowser->refreshQuickThumbImages(); + fileBrowser->applyFilter (getFilter()); // refresh total image count + _refreshProgressBar(); + } + filepanel->loadingThumbs(M("PROGRESSBAR_READY"),0); + + if (!imageToSelect_fname.empty()){ + fileBrowser->selectImage(imageToSelect_fname); + imageToSelect_fname = ""; + } + + if (!refImageForOpen_fname.empty() && actionNextPrevious!=NAV_NONE){ + fileBrowser->openNextPreviousEditorImage(refImageForOpen_fname,actionNextPrevious); + refImageForOpen_fname = ""; + actionNextPrevious = NAV_NONE; + } +} + +void FileCatalog::previewsFinished (int dir_id) { + + if ( dir_id != selectedDirectoryId ) + { + return; + } + + if (!hasValidCurrentEFS) { + MyMutex::MyLock lock(dirEFSMutex); + currentEFS = dirEFS; + } + + g_idle_add (prevfinished, this); +} + +void FileCatalog::setEnabled (bool e) { + enabled = e; +} + +void FileCatalog::redrawAll () { + fileBrowser->queue_draw (); +} + +void FileCatalog::refreshThumbImages () { + fileBrowser->refreshThumbImages (); +} + +void FileCatalog::refreshHeight () { + int newHeight = fileBrowser->getEffectiveHeight(); + if (newHeight < 5) { // This may occure if there's no thumbnail. + int w, h; + get_size_request(w, h); + newHeight = h; + } + if (hbToolBar1->is_visible() && !options.FileBrowserToolbarSingleRow) + newHeight += hbToolBar1->get_height(); + if (buttonBar->is_visible()) + newHeight += buttonBar->get_height(); + set_size_request(0, newHeight+2); // HOMBRE: yeah, +2, there's always 2 pixels missing... sorry for this dirty hack O:) +} + +void FileCatalog::_openImage (std::vector tmb) { + + if (enabled && listener!=NULL) { + bool continueToLoad=true; + for (size_t i=0; i< tmb.size() && continueToLoad; i++) { + // Open the image here, and stop if in Single Editor mode, or if an image couldn't + // be opened, would it be because the file doesn't exist or because of lack of RAM + if( !(listener->fileSelected (tmb[i])) && !options.tabbedUI ) + continueToLoad = false; + tmb[i]->decreaseRef (); + } + } +} + +struct FCOIParams { + FileCatalog* catalog; + std::vector tmb; +}; + +int openRequestedUI (void* p) { + FCOIParams* params = static_cast(p); + params->catalog->_openImage (params->tmb); + delete params; + + return 0; +} + +void FileCatalog::openRequested (std::vector tmb) { + + FCOIParams* params = new FCOIParams; + params->catalog = this; + params->tmb = tmb; + for (size_t i=0; iincreaseRef (); + g_idle_add (openRequestedUI, params); +} + +void FileCatalog::deleteRequested (std::vector tbe, bool inclBatchProcessed) { + + if (tbe.empty()) + return; + + Gtk::MessageDialog msd (M("FILEBROWSER_DELETEDLGLABEL"), true, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true); + msd.set_secondary_text(Glib::ustring::compose ( inclBatchProcessed ? M("FILEBROWSER_DELETEDLGMSGINCLPROC") : M("FILEBROWSER_DELETEDLGMSG"), tbe.size()), true); + + if (msd.run()==Gtk::RESPONSE_YES) { + for (unsigned int i=0; ifilename; + // remove from browser + FileBrowserEntry* t = fileBrowser->delEntry (fname); +// t->thumbnail->decreaseRef (); + delete t; + // remove from cache + cacheMgr->deleteEntry (fname); + // delete from file system + safe_g_remove (fname); + // delete paramfile if found + safe_g_remove (Glib::ustring(fname+paramFileExtension)); + safe_g_remove (Glib::ustring(removeExtension(fname)+paramFileExtension)); + // delete .thm file + safe_g_remove (Glib::ustring(removeExtension(fname)+".thm")); + safe_g_remove (Glib::ustring(removeExtension(fname)+".THM")); + + if (inclBatchProcessed) { + Glib::ustring procfName = Glib::ustring::compose ("%1.%2", BatchQueue::calcAutoFileNameBase(fname), options.saveFormatBatch.format); + if (safe_file_test (procfName, Glib::FILE_TEST_EXISTS)) safe_g_remove (procfName); + + // delete paramfile if found + Glib::ustring procfNameParamFile = Glib::ustring::compose ("%1.%2.out%3", BatchQueue::calcAutoFileNameBase(fname), options.saveFormatBatch.format, paramFileExtension); + if (safe_file_test (procfNameParamFile, Glib::FILE_TEST_EXISTS)) safe_g_remove (procfNameParamFile); + } + + previewsLoaded--; + } + + _refreshProgressBar(); + redrawAll (); + } +} + + +void FileCatalog::copyMoveRequested (std::vector tbe, bool moveRequested) { + + if (tbe.empty()) + return; + + + Glib::ustring fc_title; + if (moveRequested) fc_title=M("FILEBROWSER_POPUPMOVETO"); + else fc_title=M("FILEBROWSER_POPUPCOPYTO"); + Gtk::FileChooserDialog fc(fc_title,Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER ); + fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + fc.add_button( Gtk::StockID("gtk-ok"), Gtk::RESPONSE_OK); + // open dialog at the 1-st file's path + fc.set_filename(tbe[0]->filename); + //!!! TODO prevent dialog closing on "enter" key press + + bool filecopymovecomplete; + int i_copyindex; + + if( fc.run() == Gtk::RESPONSE_OK ){ + Glib::ustring dest_Dir = fc.get_current_folder(); + + // iterate through selected files + for (unsigned int i=0; ifilename; + Glib::ustring src_Dir = Glib::path_get_dirname(src_fPath); + Glib::RefPtr src_file = Gio::File::create_for_path ( src_fPath ); + if( !src_file ) continue; // if file is missing - skip it + + Glib::ustring fname=src_file->get_basename(); + Glib::ustring fname_noExt = removeExtension(fname); + Glib::ustring fname_Ext = getExtension(fname); + + // construct destination File Paths + Glib::ustring dest_fPath = Glib::build_filename (dest_Dir, fname); + Glib::ustring dest_fPath_param= dest_fPath + paramFileExtension; + + if (moveRequested && (src_Dir==dest_Dir)) continue; + /* comparison of src_Dir and dest_Dir is done per image for compatibility with + possible future use of Collections as source where each file's source path may be different.*/ + + filecopymovecomplete = false; + i_copyindex = 1; + while(!filecopymovecomplete){ + // check for filename conflicts at destination - prevent overwriting (actually RT will crash on overwriting attempt) + if (!safe_file_test(dest_fPath, Glib::FILE_TEST_EXISTS) && !safe_file_test(dest_fPath_param, Glib::FILE_TEST_EXISTS)){ + // copy/move file to destination + Glib::RefPtr dest_file = Gio::File::create_for_path ( dest_fPath ); + if (moveRequested) { + // move file + src_file->move(dest_file); + // re-attach cache files + cacheMgr->renameEntry (src_fPath, tbe[i]->thumbnail->getMD5(), dest_fPath); + // remove from browser + fileBrowser->delEntry (src_fPath); + + previewsLoaded--; + } + else + src_file->copy(dest_file); + + + // attempt to copy/move paramFile only if it exist next to the src + Glib::RefPtr scr_param = Gio::File::create_for_path ( src_fPath + paramFileExtension ); + + if (safe_file_test( src_fPath + paramFileExtension, Glib::FILE_TEST_EXISTS)){ + Glib::RefPtr dest_param = Gio::File::create_for_path ( dest_fPath_param); + // copy/move paramFile to destination + if (moveRequested){ + if (safe_file_test( dest_fPath + paramFileExtension, Glib::FILE_TEST_EXISTS)){ + // profile already got copied to destination from cache after cacheMgr->renameEntry + // delete source profile as cleanup + safe_g_remove (src_fPath + paramFileExtension); + } + else + scr_param->move(dest_param); + } + else + scr_param->copy(dest_param); + } + filecopymovecomplete = true; + } + else{ + // adjust destination fname to avoid conflicts (append "_", preserve extension) + Glib::ustring dest_fname = Glib::ustring::compose("%1%2%3%4%5",fname_noExt,"_",i_copyindex,".",fname_Ext); + // re-construct destination File Paths + dest_fPath = Glib::build_filename (dest_Dir, dest_fname); + dest_fPath_param= dest_fPath + paramFileExtension; + i_copyindex++; + } + }//while + } // i tbe, bool fastmode) { + + if (listener) { + std::vector entries; + + // TODO: (HOMBRE) should we still use parallelization here, now that thumbnails are processed asynchronously...? + //#pragma omp parallel for ordered + for (size_t i=0; ithumbnail; + rtengine::procparams::ProcParams params = th->getProcParams(); + + // if fast mode is selected, override (disable) params + // controlling time and resource consuming tasks + // and also those which effect is not pronounced after reducing the image size + // TODO!!! could expose selections below via preferences + if (fastmode){ + if (options.fastexport_bypass_sharpening ) params.sharpening.enabled = false; + if (options.fastexport_bypass_sharpenEdge ) params.sharpenEdge.enabled = false; + if (options.fastexport_bypass_sharpenMicro ) params.sharpenMicro.enabled = false; + //if (options.fastexport_bypass_lumaDenoise ) params.lumaDenoise.enabled = false; + //if (options.fastexport_bypass_colorDenoise ) params.colorDenoise.enabled = false; + if (options.fastexport_bypass_defringe ) params.defringe.enabled = false; + if (options.fastexport_bypass_dirpyrDenoise ) params.dirpyrDenoise.enabled = false; + if (options.fastexport_bypass_sh_hq ) params.sh.hq = false; + if (options.fastexport_bypass_dirpyrequalizer ) params.dirpyrequalizer.enabled = false; + if (options.fastexport_bypass_wavelet ) params.wavelet.enabled = false; + //if (options.fastexport_bypass_raw_bayer_all_enhance ) params.raw.bayersensor.all_enhance = false; + if (options.fastexport_bypass_raw_bayer_dcb_iterations ) params.raw.bayersensor.dcb_iterations = 0; + if (options.fastexport_bypass_raw_bayer_dcb_enhance ) params.raw.bayersensor.dcb_enhance = false; + if (options.fastexport_bypass_raw_bayer_lmmse_iterations) params.raw.bayersensor.lmmse_iterations = 0; + if (options.fastexport_bypass_raw_bayer_linenoise ) params.raw.bayersensor.linenoise = 0; + if (options.fastexport_bypass_raw_bayer_greenthresh ) params.raw.bayersensor.greenthresh = 0; + if (options.fastexport_bypass_raw_ccSteps ) {params.raw.bayersensor.ccSteps = params.raw.xtranssensor.ccSteps = 0;} + if (options.fastexport_bypass_raw_ca ) {params.raw.ca_autocorrect = false; params.raw.cared=0; params.raw.cablue=0;} + if (options.fastexport_bypass_raw_df ) {params.raw.df_autoselect = false; params.raw.dark_frame="";} + if (options.fastexport_bypass_raw_ff ) {params.raw.ff_AutoSelect = false; params.raw.ff_file="";} + params.raw.bayersensor.method = options.fastexport_raw_bayer_method ; + params.raw.xtranssensor.method = options.fastexport_raw_xtrans_method; + params.icm.input = options.fastexport_icm_input ; + params.icm.working = options.fastexport_icm_working ; + params.icm.output = options.fastexport_icm_output ; + params.icm.gamma = options.fastexport_icm_gamma ; + params.resize.enabled = options.fastexport_resize_enabled ; + params.resize.scale = options.fastexport_resize_scale ; + params.resize.appliesTo = options.fastexport_resize_appliesTo ; + params.resize.method = options.fastexport_resize_method ; + params.resize.dataspec = options.fastexport_resize_dataspec ; + params.resize.width = options.fastexport_resize_width ; + params.resize.height = options.fastexport_resize_height ; + } + + rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType()==FT_Raw, params); + + int pw; + int ph = BatchQueue::calcMaxThumbnailHeight(); + th->getThumbnailSize (pw, ph); + + // processThumbImage is the processing intensive part, but adding to queue must be ordered + //#pragma omp ordered + //{ + BatchQueueEntry* bqh = new BatchQueueEntry (pjob, params, fbe->filename, pw, ph, th); + entries.push_back(bqh); + //} + } + + listener->addBatchQueueJobs( entries ); + } +} + +void FileCatalog::exportRequested (){ + +} + +void FileCatalog::setExportPanel (ExportPanel* expanel) { + + exportPanel = expanel; + exportPanel->set_sensitive (false); + exportPanel->setExportPanelListener (this); + fileBrowser->setExportPanel(expanel); +} + +void FileCatalog::renameRequested (std::vector tbe) { + + bool success; + + RenameDialog* renameDlg = new RenameDialog ((Gtk::Window*)get_toplevel()); + + for (size_t i=0; iinitName (Glib::path_get_basename (tbe[i]->filename), tbe[i]->thumbnail->getCacheImageData()); + + Glib::ustring ofname = tbe[i]->filename; + Glib::ustring dirName = Glib::path_get_dirname (tbe[i]->filename); + Glib::ustring baseName = Glib::path_get_basename (tbe[i]->filename); + + success = false; + do { + if (renameDlg->run ()== Gtk::RESPONSE_OK) { + Glib::ustring nBaseName = renameDlg->getNewName (); + // if path has directory components, exit + if (Glib::path_get_dirname (nBaseName) != ".") + continue; + // if no extension is given, concatenate the extension of the original file + Glib::ustring ext = getExtension (nBaseName); + if (ext.empty()) + nBaseName += "." + getExtension (baseName); + Glib::ustring nfname = Glib::build_filename (dirName, nBaseName); + + /* check if filename already exists*/ + if (safe_file_test (nfname, Glib::FILE_TEST_EXISTS)) { + Glib::ustring msg_ = Glib::ustring("") + nfname + ": " + M("MAIN_MSG_ALREADYEXISTS") + ""; + Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd.run (); + } + else { + success = true; + if (!safe_g_rename (ofname, nfname)) { + cacheMgr->renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); + safe_g_remove(ofname + paramFileExtension); + reparseDirectory (); + } + } + } + else + success = true; + } while (!success); + renameDlg->hide (); + } + delete renameDlg; +/* // ask for new file name + Gtk::Dialog dialog (M("FILEBROWSER_RENAMEDLGLABEL"), *((Gtk::Window*)get_toplevel()), true, true); + + dialog.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); + dialog.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + + Gtk::Label l; + dialog.get_vbox()->pack_start (l, Gtk::PACK_SHRINK); + + Gtk::Entry nfentry; + + dialog.get_vbox()->pack_start (nfentry, Gtk::PACK_SHRINK); + dialog.get_vbox()->show_all (); + + nfentry.set_activates_default (true); + dialog.set_default_response (Gtk::RESPONSE_OK); + + for (int i=0; ifilename; + Glib::ustring dirName = Glib::path_get_dirname (tbe[i]->filename); + Glib::ustring baseName = Glib::path_get_basename (tbe[i]->filename); + + l.set_markup (Glib::ustring("") + Glib::ustring::compose (M("FILEBROWSER_RENAMEDLGMSG"), baseName) + Glib::ustring("")); + nfentry.set_text (baseName); + nfentry.select_region (0, baseName.size()); + + if (dialog.run ()== Gtk::RESPONSE_OK) { + Glib::ustring nBaseName = nfentry.get_text (); + // if path has directory components, exit + if (Glib::path_get_dirname (nBaseName) != ".") + continue; + // if no extension is given, concatenate the extension of the original file + if (nBaseName.find ('.')==nBaseName.npos) { + size_t lastdot = baseName.find_last_of ('.'); + nBaseName += "." + (lastdot!=Glib::ustring::npos ? baseName.substr (lastdot+1) : ""); + } + Glib::ustring nfname = Glib::build_filename (dirName, nBaseName); + if (!safe_g_rename (ofname, nfname)) { + cacheMgr->renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); + // the remaining part (removing old and adding new entry) is done by the directory monitor + reparseDirectory (); +// on_dir_changed (Gio::File::create_for_path (nfname), Gio::File::create_for_path (nfname), Gio::FILE_MONITOR_EVENT_CHANGED, true); + } + } + } + */ +} + +void FileCatalog::clearFromCacheRequested (std::vector tbe, bool leavenotrace) { + + if (tbe.empty()) + return; + + for (unsigned int i=0; ifilename; + // remove from cache + cacheMgr->clearFromCache (fname,leavenotrace); + } +} + +void FileCatalog::categoryButtonToggled (Gtk::ToggleButton* b, bool isMouseClick) { + + //was control key pressed + bool control_down = modifierKey & GDK_CONTROL_MASK; + + //was shift key pressed + bool shift_down = modifierKey & GDK_SHIFT_MASK; + + // The event is process here, we can clear modifierKey now, it'll be set again on the next even + modifierKey = 0; + + const int numCateg = sizeof(bCateg) / sizeof(bCateg[0]); + const int numButtons = sizeof(categoryButtons) / sizeof(categoryButtons[0]); + + for (int i=0; iset_active(!b->get_active()); + + //if both control and shift keys were pressed, do nothing + if (!(control_down && shift_down)) { + + fileBrowser->getScrollPosition (hScrollPos[lastScrollPos], vScrollPos[lastScrollPos]); + + //we look how many stars are already toggled on, if any + int toggled_stars_count=0, buttons=0, start_star=0, toggled_button=0; + + for (int i=0; iget_active()) { + if (i>0 && i<17) { + toggled_stars_count ++; + start_star = i; + } + buttons |= (1 << i); + } + if (categoryButtons[i] == b) toggled_button = i; + } + + // if no modifier key is pressed, + if (!(control_down || shift_down)) { + // if we're deselecting non-trashed + if (toggled_button == 18 && (buttons & (1 << toggled_button))) { + categoryButtons[0]->set_active (true); + for (int i=1; iset_active (false); + } + // if we're deselecting the only star still active + else if (toggled_stars_count == 1 && (buttons & (1 << toggled_button))) { + // activate clear-filters + categoryButtons[0]->set_active (true); + // deactivate the toggled filter + categoryButtons[toggled_button]->set_active (false); + } + // if we're deselecting trash + else if (toggled_button == 17 && (buttons & (1 << toggled_button))) { + categoryButtons[0]->set_active (true); + categoryButtons[17]->set_active (false); + } + else { + // activate the toggled filter, deactivate the rest + for (int i=0; iset_active (i==toggled_button); + } + } + //modifier key allowed only for stars and color labels... + else if (toggled_button>0 && toggled_button<17) { + if (control_down) { + //control is pressed + if (toggled_stars_count == 1 && (buttons & (1 << toggled_button))) { + //we're deselecting the only star still active, so we activate clear-filters + categoryButtons[0]->set_active(true); + //and we deselect the toggled star + categoryButtons[toggled_button]->set_active (false); + } + else if (toggled_stars_count >= 1) { + //we toggle the state of a star (eventually another one than the only one selected) + categoryButtons[toggled_button]->set_active(!categoryButtons[toggled_button]->get_active()); + } + else { + //no star selected + //we deselect the 2 non star filters + if (buttons & 1 ) categoryButtons[0]->set_active(false); + if (buttons & (1 << 17)) categoryButtons[17]->set_active(false); + //and we toggle on the star + categoryButtons[toggled_button]->set_active (true); + } + } + else { + //shift is pressed, only allowed if 0 or 1 star & labels is selected + if (!toggled_stars_count) { + //we deselect the 2 non star filters + if (buttons & 1 ) categoryButtons[0]->set_active(false); + if (buttons & (1 << 7)) categoryButtons[7]->set_active(false); + if (buttons & (1 << 13)) categoryButtons[13]->set_active(false); + if (buttons & (1 << 17)) categoryButtons[17]->set_active(false); + //and we set the start star to 1 (unrated images) + start_star = 1; + //we act as if one star were selected + toggled_stars_count = 1; + } + if (toggled_stars_count == 1) { + int current_star=min(start_star,toggled_button); + int last_star =max(start_star,toggled_button); + //we permute the start and the end star for the next loop + for (; current_star <= last_star; current_star++) { + //we toggle on all the star in the range + if (!(buttons & (1 << current_star))) categoryButtons[current_star]->set_active(true); + } + } + //if more than one star & color label is selected, do nothing + } + } + // ...or non-trashed with Control modifier + else if (toggled_button == 18 && control_down) + { + bNotTrash->set_active (!bNotTrash->get_active ()); + } + + bool active_now, active_before; + + // FilterClear: set the right images + // TODO: swapping FilterClear icon needs more work in categoryButtonToggled + /*active_now = bFilterClear->get_active(); + active_before = buttons & (1 << (0)); // 0 + if ( active_now && !active_before) bFilterClear->set_image (*iFilterClear); + else if (!active_now && active_before) bFilterClear->set_image (*igFilterClear);*/ + + // rank: set the right images + for (int i=0; i<5; i++) { + active_now = bRank[i]->get_active(); + active_before = buttons & (1 << (i+2)); // 2,3,4,5,6 + if ( active_now && !active_before) bRank[i]->set_image (*iranked[i]); + else if (!active_now && active_before) bRank[i]->set_image (*igranked[i]); + } + active_now = bUnRanked->get_active(); + active_before = buttons & (1 << (1)); // 1 + if ( active_now && !active_before) bUnRanked->set_image (*iUnRanked); + else if (!active_now && active_before) bUnRanked->set_image (*igUnRanked); + + // color labels: set the right images + for (int i=0; i<5; i++) { + active_now = bCLabel[i]->get_active(); + active_before = buttons & (1 << (i+8)); // 8,9,10,11,12 + if ( active_now && !active_before) bCLabel[i]->set_image (*iCLabeled[i]); + else if (!active_now && active_before) bCLabel[i]->set_image (*igCLabeled[i]); + } + active_now = bUnCLabeled->get_active(); + active_before = buttons & (1 << (7)); // 7 + if ( active_now && !active_before) bUnCLabeled->set_image (*iUnCLabeled); + else if (!active_now && active_before) bUnCLabeled->set_image (*igUnCLabeled); + + // Edited: set the right images + for (int i=0; i<2; i++) { + active_now = bEdited[i]->get_active(); + active_before = buttons & (1 << (i+13)); //13,14 + if ( active_now && !active_before) bEdited[i]->set_image (*iEdited[i]); + else if (!active_now && active_before) bEdited[i]->set_image (*igEdited[i]); + } + + // RecentlySaved: set the right images + for (int i=0; i<2; i++) { + active_now = bRecentlySaved[i]->get_active(); + active_before = buttons & (1 << (i+15));//15,16 + if ( active_now && !active_before) bRecentlySaved[i]->set_image (*iRecentlySaved[i]); + else if (!active_now && active_before) bRecentlySaved[i]->set_image (*igRecentlySaved[i]); + } + + fileBrowser->applyFilter (getFilter ()); + _refreshProgressBar(); + + //rearrange panels according to the selected filter + removeIfThere (hBox, trashButtonBox); + if (bTrash->get_active ()) + hBox->pack_start (*trashButtonBox, Gtk::PACK_SHRINK, 4); + hBox->queue_draw (); + + fileBrowser->setScrollPosition (hScrollPos[lastScrollPos], vScrollPos[lastScrollPos]); + } + + for (int i=0; iget_active () || bRank[0]->get_active () || bRank[1]->get_active () || bRank[2]->get_active () || bRank[3]->get_active () || bRank[4]->get_active (); + bool anyCLabelFilterActive = bUnCLabeled->get_active () || bCLabel[0]->get_active ()|| bCLabel[1]->get_active ()|| bCLabel[2]->get_active ()|| bCLabel[3]->get_active ()|| bCLabel[4]->get_active (); + bool anyEditedFilterActive = bEdited[0]->get_active() || bEdited[1]->get_active(); + bool anyRecentlySavedFilterActive = bRecentlySaved[0]->get_active() || bRecentlySaved[1]->get_active(); + const bool nonTrashedActive = bNotTrash->get_active(); + /* + * filter is setup in 2 steps + * Step 1: handle individual filters + */ + filter.showRanked[0] = bFilterClear->get_active() || bUnRanked->get_active () || bTrash->get_active () || nonTrashedActive || + anyCLabelFilterActive || anyEditedFilterActive || anyRecentlySavedFilterActive; + + filter.showCLabeled[0] = bFilterClear->get_active() || bUnCLabeled->get_active () || bTrash->get_active () || nonTrashedActive || + anyRankFilterActive || anyEditedFilterActive || anyRecentlySavedFilterActive; + + for (int i=1; i<=5; i++){ + filter.showRanked[i] = bFilterClear->get_active() || bRank[i-1]->get_active () || bTrash->get_active () || nonTrashedActive || + anyCLabelFilterActive || anyEditedFilterActive || anyRecentlySavedFilterActive; + + filter.showCLabeled[i] = bFilterClear->get_active() || bCLabel[i-1]->get_active () || bTrash->get_active () || nonTrashedActive || + anyRankFilterActive || anyEditedFilterActive || anyRecentlySavedFilterActive; + } + + for (int i=0; i<2; i++){ + filter.showEdited[i] = bFilterClear->get_active() || bEdited[i]->get_active () || bTrash->get_active () || nonTrashedActive || + anyRankFilterActive || anyCLabelFilterActive || anyRecentlySavedFilterActive; + + filter.showRecentlySaved[i] = bFilterClear->get_active() || bRecentlySaved[i]->get_active () || bTrash->get_active () || nonTrashedActive || + anyRankFilterActive || anyCLabelFilterActive || anyEditedFilterActive; + } + if( options.rtSettings.verbose ){ + printf ("\n**************** FileCatalog::getFilter *** AFTER STEP 1 \n"); + for (int i=0; i<=5; i++) printf ("filter.showRanked[%i] = %i\n",i,filter.showRanked[i]); + for (int i=0; i<=5; i++) printf ("filter.showCLabeled[%i] = %i\n",i,filter.showCLabeled[i]); + for (int i=0; i<2; i++) printf ("filter.showEdited[%i] = %i\n",i,filter.showEdited[i]); + for (int i=0; i<2; i++) printf ("filter.showRecentlySaved[%i] = %i\n",i,filter.showRecentlySaved[i]); + } + filter.multiselect = false; + + /* + * Step 2 + * handle the case when more than 1 filter is selected. This overrides values set in Step + * if no filters in a group are active, filter.show for each member of that group will be set to true + * otherwise they are set based on UI input + */ + if ((anyRankFilterActive && anyCLabelFilterActive ) || + (anyRankFilterActive && anyEditedFilterActive ) || + (anyRankFilterActive && anyRecentlySavedFilterActive ) || + (anyCLabelFilterActive && anyEditedFilterActive ) || + (anyCLabelFilterActive && anyRecentlySavedFilterActive ) || + (anyEditedFilterActive && anyRecentlySavedFilterActive) || + (nonTrashedActive && (anyRankFilterActive || anyCLabelFilterActive || anyEditedFilterActive || anyRecentlySavedFilterActive))){ + + filter.multiselect = true; + filter.showRanked[0] = anyRankFilterActive?bUnRanked->get_active ():true; + filter.showCLabeled[0] = anyCLabelFilterActive?bUnCLabeled->get_active ():true; + + for (int i=1; i<=5; i++){ + filter.showRanked[i] = anyRankFilterActive?bRank[i-1]->get_active ():true; + filter.showCLabeled[i] = anyCLabelFilterActive?bCLabel[i-1]->get_active ():true; + } + for (int i=0; i<2; i++){ + filter.showEdited[i] = anyEditedFilterActive?bEdited[i]->get_active():true; + filter.showRecentlySaved[i] = anyRecentlySavedFilterActive?bRecentlySaved[i]->get_active():true; + } + if( options.rtSettings.verbose ){ + printf ("\n**************** FileCatalog::getFilter *** AFTER STEP 2 \n"); + for (int i=0; i<=5; i++) printf ("filter.showRanked[%i] = %i\n",i,filter.showRanked[i]); + for (int i=0; i<=5; i++) printf ("filter.showCLabeled[%i] = %i\n",i,filter.showCLabeled[i]); + for (int i=0; i<2; i++) printf ("filter.showEdited[%i] = %i\n",i,filter.showEdited[i]); + for (int i=0; i<2; i++) printf ("filter.showRecentlySaved[%i] = %i\n",i,filter.showRecentlySaved[i]); + printf ("filter.multiselect = %i\n",filter.multiselect); + } + } + + + filter.showTrash = bTrash->get_active () || !bNotTrash->get_active (); + filter.showNotTrash = !bTrash->get_active (); + if (!filterPanel) + filter.exifFilterEnabled = false; + else { + if (!hasValidCurrentEFS) { + MyMutex::MyLock lock(dirEFSMutex); + filter.exifFilter = dirEFS; + } + else + filter.exifFilter = currentEFS; + filter.exifFilterEnabled = filterPanel->isEnabled (); + } + + //TODO add support for more query options. e.g by date, iso, f-number, etc + //TODO could use date:;iso: etc + // default will be filename + + /* // this is for safe execution if getFilter is called before Query object is instantiated + Glib::ustring tempQuery; + tempQuery=""; + if (Query) tempQuery = Query->get_text(); + */ + filter.queryString = Query->get_text(); // full query string from Query Entry + filter.queryFileName = Query->get_text(); // for now Query is only by file name + + return filter; +} + +void FileCatalog::filterChanged () { + //TODO !!! there is too many repetitive and unnecessary executions of + // " fileBrowser->applyFilter (getFilter()); " throughout the code + // this needs further analysis and cleanup + fileBrowser->applyFilter (getFilter()); + _refreshProgressBar(); +} + +void FileCatalog::reparseDirectory () { + + if (selectedDirectory.empty()) + return; + + if (!safe_file_test (selectedDirectory, Glib::FILE_TEST_IS_DIR)) { + closeDir (); + return; + } + + std::vector nfileNameList = getFileList (); + + // check if a thumbnailed file has been deleted + const std::vector& t = fileBrowser->getEntries (); + std::vector fileNamesToDel; + for (size_t i=0; ifilename, Glib::FILE_TEST_EXISTS)) + fileNamesToDel.push_back (t[i]->filename); + for (size_t i=0; idelEntry (fileNamesToDel[i]); + cacheMgr->deleteEntry (fileNamesToDel[i]); + } + + // check if a new file has been added + for (size_t i=0; i(cat))->reparseDirectory (); + return 0; +} + +void FileCatalog::winDirChanged () { + g_idle_add(winDirChangedUITread, this); +} + +#else + +void FileCatalog::on_dir_changed (const Glib::RefPtr& file, const Glib::RefPtr& other_file, Gio::FileMonitorEvent event_type, bool internal) { + + if (options.has_retained_extention(file->get_parse_name()) + && (event_type == Gio::FILE_MONITOR_EVENT_CREATED || event_type == Gio::FILE_MONITOR_EVENT_DELETED || event_type == Gio::FILE_MONITOR_EVENT_CHANGED)) { + if (!internal) { + GThreadLock lock; + reparseDirectory (); + } + else + reparseDirectory (); + } +} + +#endif + +void FileCatalog::checkAndAddFile (Glib::RefPtr file) { + + if (!file ) + return; + if( !file->query_exists()) + return; + Glib::RefPtr info = safe_query_file_info(file); + if (info && info->get_file_type() != Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || !options.fbShowHidden)) { + size_t lastdot = info->get_name().find_last_of ('.'); + if (options.is_extention_enabled(lastdot!=Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){ + previewLoader->add (selectedDirectoryId,file->get_parse_name(),this); + previewsToLoad++; + } + } +} + +void FileCatalog::addAndOpenFile (const Glib::ustring& fname) { + + Glib::RefPtr file = Gio::File::create_for_path (fname); + if (!file ) + return; + if( !file->query_exists()) + return; + Glib::RefPtr info = safe_query_file_info(file); + if( !info ) + return; + size_t lastdot = info->get_name().find_last_of ('.'); + if (options.is_extention_enabled(lastdot!=Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){ + // if supported, load thumbnail first + Thumbnail* tmb = cacheMgr->getEntry (file->get_parse_name()); + if (tmb) { + FileBrowserEntry* entry = new FileBrowserEntry (tmb, file->get_parse_name()); + previewReady (selectedDirectoryId,entry); + // open the file + FCOIParams* params = new FCOIParams; + params->catalog = this; + params->tmb.push_back (tmb); + tmb->increaseRef (); + g_idle_add (openRequestedUI, params); + } + } +} + +void FileCatalog::emptyTrash () { + + const std::vector t = fileBrowser->getEntries (); + std::vector toDel; + for (size_t i=0; i(t[i]))->thumbnail->getStage()==1) + toDel.push_back (static_cast(t[i])); + deleteRequested (toDel, false); + trashChanged(); +} + +bool FileCatalog::trashIsEmpty () { + const std::vector t = fileBrowser->getEntries (); + for (size_t i=0; i(t[i]))->thumbnail->getStage()==1) + return false; + + return true; +} + +void FileCatalog::zoomIn () { + + fileBrowser->zoomIn (); + refreshHeight(); + +} +void FileCatalog::zoomOut () { + + fileBrowser->zoomOut (); + refreshHeight(); + +} +void FileCatalog::refreshEditedState (const std::set& efiles) { + + editedFiles = efiles; + fileBrowser->refreshEditedState (efiles); +} + +void FileCatalog::selectionChanged (std::vector tbe) { + + if (fslistener) + fslistener->selectionChanged (tbe); +} + +// Called within GTK UI thread +void FileCatalog::exifFilterChanged () { + + currentEFS = filterPanel->getFilter (); + hasValidCurrentEFS = true; + fileBrowser->applyFilter (getFilter ()); + _refreshProgressBar(); +} + +void FileCatalog::setFilterPanel (FilterPanel* fpanel) { + + filterPanel = fpanel; + filterPanel->set_sensitive (false); + filterPanel->setFilterPanelListener (this); +} +void FileCatalog::trashChanged () { + if (trashIsEmpty()) { + bTrash->set_image(*iTrashEmpty); + } + else { + bTrash->set_image(*iTrashFull); + } +} + +// Called within GTK UI thread +void FileCatalog::buttonQueryClearPressed () { + Query->set_text(""); + FileCatalog::executeQuery (); +} + +// Called within GTK UI thread +void FileCatalog::executeQuery(){ + // if BrowsePath text was changed, do a full browse; + // otherwise filter only + + if (BrowsePath->get_text()!=selectedDirectory) + buttonBrowsePathPressed (); + else + FileCatalog::filterChanged (); +} + +bool FileCatalog::Query_key_pressed (GdkEventKey *event){ + + bool shift = event->state & GDK_SHIFT_MASK; + + switch (event->keyval) { + case GDK_Escape: + // Clear Query if the Escape character is pressed within it + if (!shift){ + FileCatalog::buttonQueryClearPressed (); + return true; + } + break; + default: + break; + } + return false; +} + +void FileCatalog::updateFBQueryTB (bool singleRow) { + hbToolBar1->reference(); + if (singleRow) { + bool removed = removeIfThere(this, hbToolBar1, false); + if (removed) { + buttonBar->pack_start(*hbToolBar1, Gtk::PACK_EXPAND_WIDGET, 0); + } + } + else { + bool removed = removeIfThere(buttonBar, hbToolBar1, false); + if (removed) { + pack_start(*hbToolBar1, Gtk::PACK_SHRINK, 0); + reorder_child(*hbToolBar1, 0); + } + } + hbToolBar1->unreference(); +} + +void FileCatalog::updateFBToolBarVisibility (bool showFilmStripToolBar){ + if (showFilmStripToolBar) + showToolBar(); + else + hideToolBar(); + refreshHeight(); +} + +void FileCatalog::buttonBrowsePathPressed () { + Glib::ustring BrowsePathValue = BrowsePath->get_text(); + Glib::ustring DecodedPathPrefix=""; + Glib::ustring FirstChar; + + // handle shortcuts in the BrowsePath -- START + // read the 1-st character from the path + FirstChar = BrowsePathValue.substr (0,1); + + if (FirstChar=="~"){ // home directory + DecodedPathPrefix = Glib::get_home_dir(); + } + else if (FirstChar=="!"){ // user's pictures directory + //DecodedPathPrefix = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES); + DecodedPathPrefix = safe_get_user_picture_dir(); + } + + if (!DecodedPathPrefix.empty()){ + BrowsePathValue = Glib::ustring::compose ("%1%2",DecodedPathPrefix,BrowsePathValue.substr (1,BrowsePath->get_text_length()-1)); + BrowsePath->set_text(BrowsePathValue); + } + // handle shortcuts in the BrowsePath -- END + + // validate the path + if (safe_file_test(BrowsePathValue, Glib::FILE_TEST_IS_DIR) && dirlistener){ + dirlistener->selectDir (BrowsePathValue); + } + else + // error, likely path not found: show red arrow + buttonBrowsePath->set_image (*iRefreshRed); +} + +bool FileCatalog::BrowsePath_key_pressed (GdkEventKey *event){ + + bool shift = event->state & GDK_SHIFT_MASK; + + switch (event->keyval) { + case GDK_Escape: + // On Escape character Reset BrowsePath to selectedDirectory + if (!shift){ + BrowsePath->set_text(selectedDirectory); + // place cursor at the end + BrowsePath->select_region(BrowsePath->get_text_length(), BrowsePath->get_text_length()); + return true; + } + break; + default: + break; + } + return false; +} + +void FileCatalog::tbLeftPanel_1_visible (bool visible){ + if (visible) + tbLeftPanel_1->show(); + else + tbLeftPanel_1->hide(); +} +void FileCatalog::tbRightPanel_1_visible (bool visible){ + if (visible) + tbRightPanel_1->show(); + else + tbRightPanel_1->hide(); +} +void FileCatalog::tbLeftPanel_1_toggled () { + removeIfThere (filepanel->dirpaned, filepanel->placespaned, false); + if (tbLeftPanel_1->get_active()){ + filepanel->dirpaned->pack1 (*filepanel->placespaned, false, true); + tbLeftPanel_1->set_image (*iLeftPanel_1_Hide); + options.browserDirPanelOpened = true; + } + else { + tbLeftPanel_1->set_image (*iLeftPanel_1_Show); + options.browserDirPanelOpened = false; + } +} + +void FileCatalog::tbRightPanel_1_toggled () { + if (tbRightPanel_1->get_active()){ + filepanel->rightBox->show(); + tbRightPanel_1->set_image (*iRightPanel_1_Hide); + options.browserToolPanelOpened = true; + } + else{ + filepanel->rightBox->hide(); + tbRightPanel_1->set_image (*iRightPanel_1_Show); + options.browserToolPanelOpened = false; + } +} + +bool FileCatalog::CheckSidePanelsVisibility(){ + if(tbLeftPanel_1->get_active()==false && tbRightPanel_1->get_active()==false) + return false; + else + return true; +} +void FileCatalog::toggleSidePanels(){ + // toggle left AND right panels + + bool bAllSidePanelsVisible; + bAllSidePanelsVisible= CheckSidePanelsVisibility(); + + tbLeftPanel_1->set_active (!bAllSidePanelsVisible); + tbRightPanel_1->set_active (!bAllSidePanelsVisible); +} + +void FileCatalog::toggleLeftPanel() { + tbLeftPanel_1->set_active (!tbLeftPanel_1->get_active()); +} + +void FileCatalog::toggleRightPanel() { + tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); +} + + +void FileCatalog::selectImage (Glib::ustring fname, bool clearFilters) { + + Glib::ustring dirname = Glib::path_get_dirname(fname); + if (!dirname.empty()){ + BrowsePath->set_text(dirname); + + + if (clearFilters){ // clear all filters + Query->set_text(""); + categoryButtonToggled(bFilterClear,false); + // disable exif filters + if (filterPanel->isEnabled()) filterPanel->setEnabled (false); + } + + if (BrowsePath->get_text()!=selectedDirectory){ + // reload or refresh thumbs and select image + buttonBrowsePathPressed (); + // the actual selection of image will be handled asynchronously at the end of FileCatalog::previewsFinishedUI + imageToSelect_fname = fname; + } + else{ + // FileCatalog::filterChanged ();//this will be replaced by queue_draw() in fileBrowser->selectImage + fileBrowser->selectImage(fname); + imageToSelect_fname = ""; + } + } +} + + +void FileCatalog::openNextPreviousEditorImage (Glib::ustring fname, bool clearFilters, eRTNav nextPrevious) { + + Glib::ustring dirname = Glib::path_get_dirname(fname); + if (!dirname.empty()){ + BrowsePath->set_text(dirname); + + + if (clearFilters){ // clear all filters + Query->set_text(""); + categoryButtonToggled(bFilterClear,false); + // disable exif filters + if (filterPanel->isEnabled()) filterPanel->setEnabled (false); + } + + if (BrowsePath->get_text()!=selectedDirectory){ + // reload or refresh thumbs and select image + buttonBrowsePathPressed (); + // the actual selection of image will be handled asynchronously at the end of FileCatalog::previewsFinishedUI + refImageForOpen_fname = fname; + actionNextPrevious = nextPrevious; + } + else{ + // FileCatalog::filterChanged ();//this was replace by queue_draw() in fileBrowser->selectImage + fileBrowser->openNextPreviousEditorImage(fname,nextPrevious); + refImageForOpen_fname = ""; + actionNextPrevious = NAV_NONE; + } + } +} + +bool FileCatalog::handleShortcutKey (GdkEventKey* event) { + + bool ctrl = event->state & GDK_CONTROL_MASK; + bool shift = event->state & GDK_SHIFT_MASK; + bool alt = event->state & GDK_MOD1_MASK; +#ifdef __WIN32__ + bool altgr = event->state & GDK_MOD2_MASK; +#else + bool altgr = event->state & GDK_MOD5_MASK; +#endif + modifierKey = event->state; + + // GUI Layout + switch(event->keyval) { + case GDK_l: + if (!alt)tbLeftPanel_1->set_active (!tbLeftPanel_1->get_active()); // toggle left panel + if (alt && !ctrl) tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); // toggle right panel + if (alt && ctrl) { + tbLeftPanel_1->set_active (!tbLeftPanel_1->get_active()); // toggle left panel + tbRightPanel_1->set_active (!tbRightPanel_1->get_active()); // toggle right panel + } + return true; + case GDK_m: + if (!ctrl && !alt) toggleSidePanels(); + return true; + } + + if (shift){ + switch(event->keyval) { + case GDK_Escape: + BrowsePath->set_text(selectedDirectory); + // set focus on something neutral, this is useful to remove focus from BrowsePath and Query + // when need to execute a shortcut, which otherwise will be typed into those fields + filepanel->grab_focus(); + return true; + } + } + +#ifdef __WIN32__ + if (!alt && !shift && !altgr) { // shift is reserved for ranking + switch(event->hardware_keycode) { + case 0x30: + categoryButtonToggled(bUnRanked,false); + return true; + case 0x31: + categoryButtonToggled(bRank[0],false); + return true; + case 0x32: + categoryButtonToggled(bRank[1],false); + return true; + case 0x33: + categoryButtonToggled(bRank[2],false); + return true; + case 0x34: + categoryButtonToggled(bRank[3],false); + return true; + case 0x35: + categoryButtonToggled(bRank[4],false); + return true; + case 0x36: + categoryButtonToggled(bEdited[0],false); + return true; + case 0x37: + categoryButtonToggled(bEdited[1],false); + return true; + } + } + if (!alt && !shift) { + switch(event->keyval) { + + case GDK_Return: + case GDK_KP_Enter: + if (BrowsePath->is_focus()){ + FileCatalog::buttonBrowsePathPressed (); + return true; + } + break; + } + } + + if (alt && !shift) { // shift is reserved for color labeling + switch(event->hardware_keycode) { + case 0x30: + categoryButtonToggled(bUnCLabeled,false); + return true; + case 0x31: + categoryButtonToggled(bCLabel[0],false); + return true; + case 0x32: + categoryButtonToggled(bCLabel[1],false); + return true; + case 0x33: + categoryButtonToggled(bCLabel[2],false); + return true; + case 0x34: + categoryButtonToggled(bCLabel[3],false); + return true; + case 0x35: + categoryButtonToggled(bCLabel[4],false); + return true; + case 0x36: + categoryButtonToggled(bRecentlySaved[0],false); + return true; + case 0x37: + categoryButtonToggled(bRecentlySaved[1],false); + return true; + } + } +#else + if (!alt && !shift && !altgr) { // shift is reserved for ranking + switch(event->hardware_keycode) { + case 0x13: + categoryButtonToggled(bUnRanked,false); + return true; + case 0x0a: + categoryButtonToggled(bRank[0],false); + return true; + case 0x0b: + categoryButtonToggled(bRank[1],false); + return true; + case 0x0c: + categoryButtonToggled(bRank[2],false); + return true; + case 0x0d: + categoryButtonToggled(bRank[3],false); + return true; + case 0x0e: + categoryButtonToggled(bRank[4],false); + return true; + case 0x0f: + categoryButtonToggled(bEdited[0],false); + return true; + case 0x10: + categoryButtonToggled(bEdited[1],false); + return true; + } + } + if (!alt && !shift) { + switch(event->keyval) { + + case GDK_Return: + case GDK_KP_Enter: + if (BrowsePath->is_focus()){ + FileCatalog::buttonBrowsePathPressed (); + return true; + } + break; + } + } + + if (alt && !shift) { // shift is reserved for color labeling + switch(event->hardware_keycode) { + case 0x13: + categoryButtonToggled(bUnCLabeled,false); + return true; + case 0x0a: + categoryButtonToggled(bCLabel[0],false); + return true; + case 0x0b: + categoryButtonToggled(bCLabel[1],false); + return true; + case 0x0c: + categoryButtonToggled(bCLabel[2],false); + return true; + case 0x0d: + categoryButtonToggled(bCLabel[3],false); + return true; + case 0x0e: + categoryButtonToggled(bCLabel[4],false); + return true; + case 0x0f: + categoryButtonToggled(bRecentlySaved[0],false); + return true; + case 0x10: + categoryButtonToggled(bRecentlySaved[1],false); + return true; + } + } +#endif + if (!ctrl && !alt) { + switch(event->keyval) { + case GDK_d: + case GDK_D: + categoryButtonToggled(bFilterClear,false); + return true; + } + } + + if (!ctrl || (alt && !options.tabbedUI)) { + switch(event->keyval) { + + case GDK_bracketright: + coarsePanel->rotateRight(); + return true; + case GDK_bracketleft: + coarsePanel->rotateLeft(); + return true; + case GDK_i: + case GDK_I: + exifInfo->set_active (!exifInfo->get_active()); + return true; + + case GDK_plus: + case GDK_equal: + zoomIn(); + return true; + case GDK_minus: + case GDK_underscore: + zoomOut(); + return true; + } + } + if (ctrl && !alt) { + switch (event->keyval) { + case GDK_o: + BrowsePath->select_region(0, BrowsePath->get_text_length()); + BrowsePath->grab_focus(); + return true; + case GDK_f: + Query->select_region(0, Query->get_text_length()); + Query->grab_focus(); + return true; + case GDK_t: + case GDK_T: + modifierKey = 0; // HOMBRE: yet another hack.... otherwise the shortcut won't work + categoryButtonToggled(bTrash,false); + return true; + } + } + if (!ctrl && !alt && shift) { + switch (event->keyval) { + case GDK_t: + case GDK_T: + if (inTabMode) { + if (options.showFilmStripToolBar) + hideToolBar(); + else + showToolBar(); + options.showFilmStripToolBar = !options.showFilmStripToolBar; + } + return true; + } + } + if (!ctrl && !alt && !shift) { + switch (event->keyval) { + case GDK_t: + case GDK_T: + if (inTabMode) { + if (options.showFilmStripToolBar) + hideToolBar(); + else + showToolBar(); + options.showFilmStripToolBar = !options.showFilmStripToolBar; + } + refreshHeight(); + return true; + } + } + + if (fileBrowser->keyPressed(event)) + return true; + + return false; +} + +void FileCatalog::showToolBar() { + if (!options.FileBrowserToolbarSingleRow) + hbToolBar1->show(); + buttonBar->show(); +} + +void FileCatalog::hideToolBar() { + if (!options.FileBrowserToolbarSingleRow) + hbToolBar1->hide(); + buttonBar->hide(); +} diff --git a/rtgui/filepanel.h b/rtgui/filepanel.h index 834564ba4..d5fd7fad2 100644 --- a/rtgui/filepanel.h +++ b/rtgui/filepanel.h @@ -1,107 +1,107 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _FILEPANEL_ -#define _FILEPANEL_ - -#include -#include "batchtoolpanelcoord.h" -#include "filecatalog.h" -#include "dirbrowser.h" -#include "fileselectionlistener.h" -#include "placesbrowser.h" -#include "recentbrowser.h" -#include "pparamschangelistener.h" -#include "history.h" -#include "filterpanel.h" -#include "exportpanel.h" -#include "progressconnector.h" - -class RTWindow; -class FilePanel : public Gtk::HPaned, - public FileSelectionListener, - public PParamsChangeListener -{ - - protected: - //DirBrowser* dirBrowser; - PlacesBrowser* placesBrowser; - RecentBrowser* recentBrowser; - // FileCatalog* fileCatalog; // filecatalog is the file browser with the button bar above it - - Inspector* inspectorPanel; - Gtk::VPaned* tpcPaned; - BatchToolPanelCoordinator* tpc; - History* history; - //FilterPanel* filterPanel; - RTWindow* parent; - Gtk::Notebook* rightNotebook; - sigc::connection rightNotebookSwitchConn; - - struct pendingLoad { - bool complete; - ProgressConnector *pc; - Thumbnail *thm; - }; - MyMutex pendingLoadMutex; - std::vector pendingLoads; - - int error; - - void on_NB_switch_page(GtkNotebookPage* page, guint page_num); - - public: - FilePanel (); - ~FilePanel (); - - Gtk::Paned* placespaned; - Gtk::HPaned* dirpaned; - - Gtk::HBox* rightBox; - - DirBrowser* dirBrowser; - FilterPanel* filterPanel; - ExportPanel* exportPanel; - FileCatalog* fileCatalog; - Gtk::Paned *ribbonPane; - - void setParent (RTWindow* p) { parent = p; } - void init (); // dont call it directly, the constructor calls it as idle source - void on_realize (); - void setAspect(); - void open (const Glib::ustring& d); // open a file or a directory - void refreshEditedState (const std::set& efiles) { fileCatalog->refreshEditedState (efiles); } - void loadingThumbs(Glib::ustring str, double rate); - - // call this before closing RT: it saves file browser's related things into options - void saveOptions (); - - // interface fileselectionlistener - bool fileSelected (Thumbnail* thm); - bool addBatchQueueJobs ( std::vector &entries ); - - void optionsChanged (); - bool imageLoaded( Thumbnail* thm, ProgressConnector * ); - - bool handleShortcutKey (GdkEventKey* event); - void updateTPVScrollbar (bool hide); - void updateTabsUsesIcons (bool useIcons); -}; - -#endif - +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _FILEPANEL_ +#define _FILEPANEL_ + +#include +#include "batchtoolpanelcoord.h" +#include "filecatalog.h" +#include "dirbrowser.h" +#include "fileselectionlistener.h" +#include "placesbrowser.h" +#include "recentbrowser.h" +#include "pparamschangelistener.h" +#include "history.h" +#include "filterpanel.h" +#include "exportpanel.h" +#include "progressconnector.h" + +class RTWindow; +class FilePanel : public Gtk::HPaned, + public FileSelectionListener, + public PParamsChangeListener +{ + + protected: + //DirBrowser* dirBrowser; + PlacesBrowser* placesBrowser; + RecentBrowser* recentBrowser; + // FileCatalog* fileCatalog; // filecatalog is the file browser with the button bar above it + + Inspector* inspectorPanel; + Gtk::VPaned* tpcPaned; + BatchToolPanelCoordinator* tpc; + History* history; + //FilterPanel* filterPanel; + RTWindow* parent; + Gtk::Notebook* rightNotebook; + sigc::connection rightNotebookSwitchConn; + + struct pendingLoad { + bool complete; + ProgressConnector *pc; + Thumbnail *thm; + }; + MyMutex pendingLoadMutex; + std::vector pendingLoads; + + int error; + + void on_NB_switch_page(GtkNotebookPage* page, guint page_num); + + public: + FilePanel (); + ~FilePanel (); + + Gtk::Paned* placespaned; + Gtk::HPaned* dirpaned; + + Gtk::HBox* rightBox; + + DirBrowser* dirBrowser; + FilterPanel* filterPanel; + ExportPanel* exportPanel; + FileCatalog* fileCatalog; + Gtk::Paned *ribbonPane; + + void setParent (RTWindow* p) { parent = p; } + void init (); // dont call it directly, the constructor calls it as idle source + void on_realize (); + void setAspect(); + void open (const Glib::ustring& d); // open a file or a directory + void refreshEditedState (const std::set& efiles) { fileCatalog->refreshEditedState (efiles); } + void loadingThumbs(Glib::ustring str, double rate); + + // call this before closing RT: it saves file browser's related things into options + void saveOptions (); + + // interface fileselectionlistener + bool fileSelected (Thumbnail* thm); + bool addBatchQueueJobs ( std::vector &entries ); + + void optionsChanged (); + bool imageLoaded( Thumbnail* thm, ProgressConnector * ); + + bool handleShortcutKey (GdkEventKey* event); + void updateTPVScrollbar (bool hide); + void updateTabsUsesIcons (bool useIcons); +}; + +#endif + diff --git a/rtgui/filmsimulation.cc b/rtgui/filmsimulation.cc index 4e63d7058..b17760319 100644 --- a/rtgui/filmsimulation.cc +++ b/rtgui/filmsimulation.cc @@ -1,264 +1,264 @@ -#include "filmsimulation.h" -#include "options.h" -#include "../rtengine/clutstore.h" -#include "../rtengine/safegtk.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -typedef std::vector Strings; - -FilmSimulation::FilmSimulation() -: FoldableToolPanel( this, "filmsimulation", M("TP_FILMSIMULATION_LABEL"), false, true ) -{ - m_clutComboBox = Gtk::manage( new ClutComboBox() ); - int foundClutsCount = m_clutComboBox->fillFromDir( options.clutsDir ); - if ( foundClutsCount == 0 ) - { - pack_start( *Gtk::manage( new Gtk::Label( M("TP_FILMSIMULATION_ZEROCLUTSFOUND") ) ) ); - } - m_clutComboBoxConn = m_clutComboBox->signal_changed().connect( sigc::mem_fun( *this, &FilmSimulation::onClutSelected ) ); - pack_start( *m_clutComboBox ); - - m_strength = Gtk::manage( new Adjuster( M("TP_FILMSIMULATION_STRENGTH"), 0., 100, 1., 100 ) ); - m_strength->setAdjusterListener( this ); - - pack_start( *m_strength, Gtk::PACK_SHRINK, 0 ); - -} - -void FilmSimulation::onClutSelected() -{ - Glib::ustring currentClutFilename = m_clutComboBox->getSelectedClut(); - - if ( getEnabled() && !currentClutFilename.empty() && listener && currentClutFilename != m_oldClutFilename ) - { - Glib::ustring clutName, dummy; - splitClutFilename( currentClutFilename, clutName, dummy, dummy ); - listener->panelChanged( EvFilmSimulationFilename, clutName ); - - m_oldClutFilename = currentClutFilename; - } -} - -void FilmSimulation::enabledChanged () { - - if (listener) { - if (get_inconsistent()) - listener->panelChanged (EvFilmSimulationEnabled, M("GENERAL_UNCHANGED")); - else if (getEnabled()) - listener->panelChanged (EvFilmSimulationEnabled, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvFilmSimulationEnabled, M("GENERAL_DISABLED")); - } -} - -void FilmSimulation::adjusterChanged( Adjuster* a, double newval ) -{ - if (listener && (multiImage||getEnabled()) ) - { - Glib::ustring value = a->getTextValue(); - listener->panelChanged ( EvFilmSimulationStrength, value ); - } -} - -void FilmSimulation::setBatchMode( bool batchMode ) -{ - ToolPanel::setBatchMode( batchMode ); - m_clutComboBox->addUnchangedEntry(); -} - -void FilmSimulation::read( const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited ) -{ - //copypasted from lensprofile.cc & sharpening.cc - disableListener(); - updateDisable( true ); - - setEnabled (pp->filmSimulation.enabled); - if ( !pp->filmSimulation.clutFilename.empty() ) - m_clutComboBox->setSelectedClut( pp->filmSimulation.clutFilename ); - m_strength->setValue( pp->filmSimulation.strength ); - - if (pedited) - { - set_inconsistent (multiImage && !pedited->filmSimulation.enabled); - m_strength->setEditedState (pedited->filmSimulation.strength ? Edited : UnEdited); - if ( !pedited->filmSimulation.clutFilename ) - m_clutComboBox->setSelectedClut("NULL"); - } - if ( !get_inconsistent() && !pp->filmSimulation.enabled ) +#include "filmsimulation.h" +#include "options.h" +#include "../rtengine/clutstore.h" +#include "../rtengine/safegtk.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +typedef std::vector Strings; + +FilmSimulation::FilmSimulation() +: FoldableToolPanel( this, "filmsimulation", M("TP_FILMSIMULATION_LABEL"), false, true ) +{ + m_clutComboBox = Gtk::manage( new ClutComboBox() ); + int foundClutsCount = m_clutComboBox->fillFromDir( options.clutsDir ); + if ( foundClutsCount == 0 ) { - if (options.clutCacheSize == 1) - clutStore.clearCache(); - } - - updateDisable( false ); - enableListener(); -} - -void FilmSimulation::updateDisable( bool value ) -{ - m_clutComboBoxConn.block( value ); -} - -void FilmSimulation::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited ) -{ - if ( pedited ) - { - pedited->filmSimulation.enabled = !get_inconsistent(); - pedited->filmSimulation.strength = m_strength->getEditedState (); - pedited->filmSimulation.clutFilename = m_clutComboBox->getSelectedClut() != "NULL"; - } - - pp->filmSimulation.enabled = getEnabled(); - Glib::ustring clutFName = m_clutComboBox->getSelectedClut(); - if ( clutFName != "NULL" ) // We do not want to set "NULL" in clutFilename, even if "unedited" - pp->filmSimulation.clutFilename = clutFName; - pp->filmSimulation.strength = m_strength->getValue(); -} - -void FilmSimulation::setAdjusterBehavior( bool strength ) -{ - m_strength->setAddMode( strength ); -} - -void FilmSimulation::trimValues( rtengine::procparams::ProcParams* pp ) -{ - pp->filmSimulation.strength = m_strength->trimValue( pp->filmSimulation.strength ); -} - -//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -ClutComboBox::ClutColumns::ClutColumns() -{ - add( label ); - add( clutFilename ); -} - -int ClutComboBox::fillFromDir( Glib::ustring path ) -{ - int result = 0; - if ( !path.empty() ) - { - m_model.clear(); - m_model = Gtk::TreeStore::create( m_columns ); - set_model( m_model ); - result = parseDir( path, 0 ); - pack_start( m_columns.label, false ); - } - return result; -} - -Gtk::TreeIter appendToModel( Glib::RefPtr model, Gtk::TreeModel::Row *parent ) -{ - Gtk::TreeIter result; - if ( parent ) - { - result = model->append( parent->children() ); - - } - else - { - result = model->append(); - } - return result; -} - -int ClutComboBox::parseDir( Glib::ustring path, Gtk::TreeModel::Row *parentRow ) -{ - int result = 0; - if ( path.empty() || !safe_file_test( path, Glib::FILE_TEST_EXISTS ) || !safe_file_test ( path, Glib::FILE_TEST_IS_DIR ) ) - return result; - - Glib::Dir* dir = new Glib::Dir( path ); - - Strings names; - - for( Glib::DirIterator it = dir->begin(); it != dir->end(); ++it ) - { - Glib::ustring current = *it; - if ( current != "." && current != ".." ) - { - names.push_back( current ); - } - } - - std::sort( names.begin(), names.end() ); - - for ( Strings::iterator it = names.begin(); it != names.end(); ++it ) - { - Glib::ustring current = *it; - Glib::ustring fullname = Glib::build_filename( path, current ); - if ( safe_file_test( fullname, Glib::FILE_TEST_IS_DIR ) ) - { - - Gtk::TreeModel::Row newFolderMenu = *appendToModel( m_model, parentRow ); - newFolderMenu[ m_columns.label ] = current; - result += parseDir( fullname, &newFolderMenu ); - } - else - { - Glib::ustring name, extension, profileName; - splitClutFilename( current, name, extension, profileName ); - if ( extension == "tif" || - extension == "TIF" || - extension == "png" || - extension == "PNG" ) - { - Gtk::TreeModel::Row newClut = *appendToModel( m_model, parentRow ); - newClut[ m_columns.label ] = name; - newClut[ m_columns.clutFilename ] = fullname; - ++result; - } - } - } - return result; -} - -Glib::ustring ClutComboBox::getSelectedClut() -{ - Glib::ustring result; - Gtk::TreeModel::iterator current = get_active(); - Gtk::TreeModel::Row row = *current; - if ( row ) - { - result = row[ m_columns.clutFilename ]; - } - return result; -} - -void ClutComboBox::setSelectedClut( Glib::ustring filename ) -{ - if ( !filename.empty() ) - { - Gtk::TreeIter found = findRowByClutFilename( m_model->children(), filename ); - if ( found ) - { - set_active( found ); - } - } -} - -Gtk::TreeIter ClutComboBox::findRowByClutFilename( Gtk::TreeModel::Children childs, Glib::ustring filename ) -{ - Gtk::TreeIter result = childs.end(); - for( Gtk::TreeModel::Children::iterator it = childs.begin(); !result && it != childs.end(); ++it ) - { - Gtk::TreeModel::Row row = *it; - if ( row[ m_columns.clutFilename ] == filename ) - { - result = it; - } - else - { - result = findRowByClutFilename( it->children(), filename ); - } - } - return result; -} - -void ClutComboBox::addUnchangedEntry() { - Gtk::TreeModel::Row row = *(m_model->append()); - row[m_columns.label] = M("GENERAL_UNCHANGED"); - row[m_columns.clutFilename] = "NULL"; -} + pack_start( *Gtk::manage( new Gtk::Label( M("TP_FILMSIMULATION_ZEROCLUTSFOUND") ) ) ); + } + m_clutComboBoxConn = m_clutComboBox->signal_changed().connect( sigc::mem_fun( *this, &FilmSimulation::onClutSelected ) ); + pack_start( *m_clutComboBox ); + + m_strength = Gtk::manage( new Adjuster( M("TP_FILMSIMULATION_STRENGTH"), 0., 100, 1., 100 ) ); + m_strength->setAdjusterListener( this ); + + pack_start( *m_strength, Gtk::PACK_SHRINK, 0 ); + +} + +void FilmSimulation::onClutSelected() +{ + Glib::ustring currentClutFilename = m_clutComboBox->getSelectedClut(); + + if ( getEnabled() && !currentClutFilename.empty() && listener && currentClutFilename != m_oldClutFilename ) + { + Glib::ustring clutName, dummy; + splitClutFilename( currentClutFilename, clutName, dummy, dummy ); + listener->panelChanged( EvFilmSimulationFilename, clutName ); + + m_oldClutFilename = currentClutFilename; + } +} + +void FilmSimulation::enabledChanged () { + + if (listener) { + if (get_inconsistent()) + listener->panelChanged (EvFilmSimulationEnabled, M("GENERAL_UNCHANGED")); + else if (getEnabled()) + listener->panelChanged (EvFilmSimulationEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvFilmSimulationEnabled, M("GENERAL_DISABLED")); + } +} + +void FilmSimulation::adjusterChanged( Adjuster* a, double newval ) +{ + if (listener && (multiImage||getEnabled()) ) + { + Glib::ustring value = a->getTextValue(); + listener->panelChanged ( EvFilmSimulationStrength, value ); + } +} + +void FilmSimulation::setBatchMode( bool batchMode ) +{ + ToolPanel::setBatchMode( batchMode ); + m_clutComboBox->addUnchangedEntry(); +} + +void FilmSimulation::read( const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited ) +{ + //copypasted from lensprofile.cc & sharpening.cc + disableListener(); + updateDisable( true ); + + setEnabled (pp->filmSimulation.enabled); + if ( !pp->filmSimulation.clutFilename.empty() ) + m_clutComboBox->setSelectedClut( pp->filmSimulation.clutFilename ); + m_strength->setValue( pp->filmSimulation.strength ); + + if (pedited) + { + set_inconsistent (multiImage && !pedited->filmSimulation.enabled); + m_strength->setEditedState (pedited->filmSimulation.strength ? Edited : UnEdited); + if ( !pedited->filmSimulation.clutFilename ) + m_clutComboBox->setSelectedClut("NULL"); + } + if ( !get_inconsistent() && !pp->filmSimulation.enabled ) + { + if (options.clutCacheSize == 1) + clutStore.clearCache(); + } + + updateDisable( false ); + enableListener(); +} + +void FilmSimulation::updateDisable( bool value ) +{ + m_clutComboBoxConn.block( value ); +} + +void FilmSimulation::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited ) +{ + if ( pedited ) + { + pedited->filmSimulation.enabled = !get_inconsistent(); + pedited->filmSimulation.strength = m_strength->getEditedState (); + pedited->filmSimulation.clutFilename = m_clutComboBox->getSelectedClut() != "NULL"; + } + + pp->filmSimulation.enabled = getEnabled(); + Glib::ustring clutFName = m_clutComboBox->getSelectedClut(); + if ( clutFName != "NULL" ) // We do not want to set "NULL" in clutFilename, even if "unedited" + pp->filmSimulation.clutFilename = clutFName; + pp->filmSimulation.strength = m_strength->getValue(); +} + +void FilmSimulation::setAdjusterBehavior( bool strength ) +{ + m_strength->setAddMode( strength ); +} + +void FilmSimulation::trimValues( rtengine::procparams::ProcParams* pp ) +{ + pp->filmSimulation.strength = m_strength->trimValue( pp->filmSimulation.strength ); +} + +//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +ClutComboBox::ClutColumns::ClutColumns() +{ + add( label ); + add( clutFilename ); +} + +int ClutComboBox::fillFromDir( Glib::ustring path ) +{ + int result = 0; + if ( !path.empty() ) + { + m_model.clear(); + m_model = Gtk::TreeStore::create( m_columns ); + set_model( m_model ); + result = parseDir( path, 0 ); + pack_start( m_columns.label, false ); + } + return result; +} + +Gtk::TreeIter appendToModel( Glib::RefPtr model, Gtk::TreeModel::Row *parent ) +{ + Gtk::TreeIter result; + if ( parent ) + { + result = model->append( parent->children() ); + + } + else + { + result = model->append(); + } + return result; +} + +int ClutComboBox::parseDir( Glib::ustring path, Gtk::TreeModel::Row *parentRow ) +{ + int result = 0; + if ( path.empty() || !safe_file_test( path, Glib::FILE_TEST_EXISTS ) || !safe_file_test ( path, Glib::FILE_TEST_IS_DIR ) ) + return result; + + Glib::Dir* dir = new Glib::Dir( path ); + + Strings names; + + for( Glib::DirIterator it = dir->begin(); it != dir->end(); ++it ) + { + Glib::ustring current = *it; + if ( current != "." && current != ".." ) + { + names.push_back( current ); + } + } + + std::sort( names.begin(), names.end() ); + + for ( Strings::iterator it = names.begin(); it != names.end(); ++it ) + { + Glib::ustring current = *it; + Glib::ustring fullname = Glib::build_filename( path, current ); + if ( safe_file_test( fullname, Glib::FILE_TEST_IS_DIR ) ) + { + + Gtk::TreeModel::Row newFolderMenu = *appendToModel( m_model, parentRow ); + newFolderMenu[ m_columns.label ] = current; + result += parseDir( fullname, &newFolderMenu ); + } + else + { + Glib::ustring name, extension, profileName; + splitClutFilename( current, name, extension, profileName ); + if ( extension == "tif" || + extension == "TIF" || + extension == "png" || + extension == "PNG" ) + { + Gtk::TreeModel::Row newClut = *appendToModel( m_model, parentRow ); + newClut[ m_columns.label ] = name; + newClut[ m_columns.clutFilename ] = fullname; + ++result; + } + } + } + return result; +} + +Glib::ustring ClutComboBox::getSelectedClut() +{ + Glib::ustring result; + Gtk::TreeModel::iterator current = get_active(); + Gtk::TreeModel::Row row = *current; + if ( row ) + { + result = row[ m_columns.clutFilename ]; + } + return result; +} + +void ClutComboBox::setSelectedClut( Glib::ustring filename ) +{ + if ( !filename.empty() ) + { + Gtk::TreeIter found = findRowByClutFilename( m_model->children(), filename ); + if ( found ) + { + set_active( found ); + } + } +} + +Gtk::TreeIter ClutComboBox::findRowByClutFilename( Gtk::TreeModel::Children childs, Glib::ustring filename ) +{ + Gtk::TreeIter result = childs.end(); + for( Gtk::TreeModel::Children::iterator it = childs.begin(); !result && it != childs.end(); ++it ) + { + Gtk::TreeModel::Row row = *it; + if ( row[ m_columns.clutFilename ] == filename ) + { + result = it; + } + else + { + result = findRowByClutFilename( it->children(), filename ); + } + } + return result; +} + +void ClutComboBox::addUnchangedEntry() { + Gtk::TreeModel::Row row = *(m_model->append()); + row[m_columns.label] = M("GENERAL_UNCHANGED"); + row[m_columns.clutFilename] = "NULL"; +} diff --git a/rtgui/filmsimulation.h b/rtgui/filmsimulation.h index 4b05342f9..c5c447495 100644 --- a/rtgui/filmsimulation.h +++ b/rtgui/filmsimulation.h @@ -1,60 +1,60 @@ -#ifndef FILM_SIMULATION_INCLUDED -#define FILM_SIMULATION_INCLUDED - -#include -#include -#include -#include "toolpanel.h" -#include "guiutils.h" -#include "adjuster.h" - -class ClutComboBox : public MyComboBox -{ -public: - int fillFromDir( Glib::ustring path ); - Glib::ustring getSelectedClut(); - void setSelectedClut( Glib::ustring filename ); - void addUnchangedEntry(); - -private: - class ClutColumns : public Gtk::TreeModel::ColumnRecord - { - public: - Gtk::TreeModelColumn label; - Gtk::TreeModelColumn clutFilename; - ClutColumns(); - }; - - int parseDir( Glib::ustring path, Gtk::TreeModel::Row *parentRow ); - Gtk::TreeIter findRowByClutFilename( Gtk::TreeModel::Children childs, Glib::ustring filename ); - - Glib::RefPtr m_model; - ClutColumns m_columns; -}; - -class FilmSimulation : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel -{ -public: - FilmSimulation(); - - void adjusterChanged( Adjuster* a, double newval ); - void setBatchMode( bool batchMode ); - void read( const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = NULL ); - void write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = NULL ); - void setAdjusterBehavior( bool strength ); - void trimValues( rtengine::procparams::ProcParams* pp ); - -private: - void onClutSelected(); - void enabledChanged(); - - void updateDisable( bool value ); - - ClutComboBox *m_clutComboBox; - sigc::connection m_clutComboBoxConn; - Glib::ustring m_oldClutFilename; - - Adjuster *m_strength; -}; - -#endif +#ifndef FILM_SIMULATION_INCLUDED +#define FILM_SIMULATION_INCLUDED + +#include +#include +#include +#include "toolpanel.h" +#include "guiutils.h" +#include "adjuster.h" + +class ClutComboBox : public MyComboBox +{ +public: + int fillFromDir( Glib::ustring path ); + Glib::ustring getSelectedClut(); + void setSelectedClut( Glib::ustring filename ); + void addUnchangedEntry(); + +private: + class ClutColumns : public Gtk::TreeModel::ColumnRecord + { + public: + Gtk::TreeModelColumn label; + Gtk::TreeModelColumn clutFilename; + ClutColumns(); + }; + + int parseDir( Glib::ustring path, Gtk::TreeModel::Row *parentRow ); + Gtk::TreeIter findRowByClutFilename( Gtk::TreeModel::Children childs, Glib::ustring filename ); + + Glib::RefPtr m_model; + ClutColumns m_columns; +}; + +class FilmSimulation : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel +{ +public: + FilmSimulation(); + + void adjusterChanged( Adjuster* a, double newval ); + void setBatchMode( bool batchMode ); + void read( const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = NULL ); + void write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = NULL ); + void setAdjusterBehavior( bool strength ); + void trimValues( rtengine::procparams::ProcParams* pp ); + +private: + void onClutSelected(); + void enabledChanged(); + + void updateDisable( bool value ); + + ClutComboBox *m_clutComboBox; + sigc::connection m_clutComboBoxConn; + Glib::ustring m_oldClutFilename; + + Adjuster *m_strength; +}; + +#endif diff --git a/rtgui/flatcurveeditorsubgroup.cc b/rtgui/flatcurveeditorsubgroup.cc index 50ec1d1f3..31dca1bad 100644 --- a/rtgui/flatcurveeditorsubgroup.cc +++ b/rtgui/flatcurveeditorsubgroup.cc @@ -1,544 +1,544 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include "clipboard.h" -#include -#include -#include -#include "guiutils.h" -#include "multilangmgr.h" -#include "guiutils.h" -#include "mycurve.h" -#include "shcselector.h" -#include "adjuster.h" -#include "mycurve.h" -#include "myflatcurve.h" -#include "curveeditor.h" -#include "flatcurveeditorsubgroup.h" - -FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::ustring& curveDir) : CurveEditorSubGroup(curveDir) { - - valLinear = (int)FCT_Linear; - valUnchanged = (int)FCT_Unchanged; - parent = prt; - - curveBBoxPos = options.curvebboxpos; - - // ControlPoints curve - CPointsCurveBox = new Gtk::VBox (); - CPointsCurveBox->set_spacing(4); - Gtk::HBox* CPointsCurveAndButtons = Gtk::manage (new Gtk::HBox ()); - CPointsCurveAndButtons->set_spacing(4); - CPointsCurve = Gtk::manage (new MyFlatCurve ()); - CPointsCurve->set_size_request (GRAPH_SIZE+2*RADIUS+1, GRAPH_SIZE+2*RADIUS+1); - CPointsCurve->setType (FCT_MinMaxCPoints); - - Gtk::Box* CPointsbbox; // curvebboxpos 0=above, 1=right, 2=below, 3=left - if (options.curvebboxpos==1 || options.curvebboxpos==3) { - CPointsbbox = Gtk::manage (new Gtk::VBox ()); - } else { - CPointsbbox = Gtk::manage (new Gtk::HBox ()); - } - CPointsbbox->set_spacing(4); - - pasteCPoints = Gtk::manage (new Gtk::Button ()); - pasteCPoints->add (*Gtk::manage (new RTImage ("edit-paste.png"))); - copyCPoints = Gtk::manage (new Gtk::Button ()); - copyCPoints->add (*Gtk::manage (new RTImage ("edit-copy.png"))); - saveCPoints = Gtk::manage (new Gtk::Button ()); - saveCPoints->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); - loadCPoints = Gtk::manage (new Gtk::Button ()); - loadCPoints->add (*Gtk::manage (new RTImage ("gtk-open.png"))); - editCPoints = Gtk::manage (new Gtk::ToggleButton()); - editPointCPoints = Gtk::manage (new Gtk::ToggleButton ()); - editPointCPoints->add (*Gtk::manage (new RTImage ("gtk-edit.png"))); - editPointCPoints->set_tooltip_text(M("CURVEEDITOR_EDITPOINT_HINT")); - editCPoints->add (*Gtk::manage (new RTImage ("editmodehand.png"))); - editCPoints->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); - editCPoints->hide(); - - CPointsbbox->pack_end (*pasteCPoints, Gtk::PACK_SHRINK, 0); - CPointsbbox->pack_end (*copyCPoints, Gtk::PACK_SHRINK, 0); - CPointsbbox->pack_end (*saveCPoints, Gtk::PACK_SHRINK, 0); - CPointsbbox->pack_end (*loadCPoints, Gtk::PACK_SHRINK, 0); - CPointsbbox->pack_start(*editPointCPoints, Gtk::PACK_SHRINK, 0); - CPointsbbox->pack_start(*editCPoints, Gtk::PACK_SHRINK, 0); - - CPointsCurveAndButtons->pack_start (*CPointsCurve, Gtk::PACK_EXPAND_WIDGET, 0); - CPointsCurveAndButtons->pack_start (*CPointsbbox, Gtk::PACK_SHRINK, 0); - CPointsCurveBox->pack_start (*CPointsCurveAndButtons, Gtk::PACK_EXPAND_WIDGET); - if (options.curvebboxpos==0) { - removeIfThere (CPointsCurveAndButtons, CPointsbbox, false); - CPointsCurveBox->pack_start (*CPointsbbox); - CPointsCurveBox->reorder_child(*CPointsbbox, 0); - } else if (options.curvebboxpos==2) { - removeIfThere (CPointsCurveAndButtons, CPointsbbox, false); - CPointsCurveBox->pack_start (*CPointsbbox); - } else if (options.curvebboxpos==3) { - CPointsCurveAndButtons->reorder_child(*CPointsbbox, 0); - } - - { - std::vector axis; - axis.resize(4); - axis.at(0).setValues(M("CURVEEDITOR_AXIS_IN"), 5, 0.001, 0.01, 0., 1.); - axis.at(1).setValues(M("CURVEEDITOR_AXIS_OUT"), 5, 0.001, 0.01, 0., 1.); - axis.at(2).setValues(M("CURVEEDITOR_AXIS_LEFT_TAN"), 5, 0.01, 0.1, 0., 1.); - axis.at(3).setValues(M("CURVEEDITOR_AXIS_RIGHT_TAN"), 5, 0.01, 0.1, 0., 1.); - CPointsCoordAdjuster = Gtk::manage (new CoordinateAdjuster(CPointsCurve, this, axis)); - CPointsCurveBox->pack_start(*CPointsCoordAdjuster, Gtk::PACK_SHRINK, 0); - if (options.curvebboxpos == 2) - CPointsCurveBox->reorder_child(*CPointsCoordAdjuster, 2); - CPointsCoordAdjuster->show_all(); - } - - CPointsCurveBox->show_all (); - CPointsCoordAdjuster->hide(); - - saveCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::savePressed) ); - loadCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::loadPressed) ); - copyCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::copyPressed) ); - pasteCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::pastePressed) ); - editPointCPointsConn = editPointCPoints->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &FlatCurveEditorSubGroup::editPointToggled), editPointCPoints) ); - editCPointsConn = editCPoints->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &FlatCurveEditorSubGroup::editToggled), editCPoints) ); - - saveCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); - loadCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); - copyCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); - pasteCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); - - CPointsCurve->setCurveListener (parent); // Send the message directly to the parent -} - -FlatCurveEditorSubGroup::~FlatCurveEditorSubGroup() { - delete CPointsCurveBox; -} - -/* - * Add a new curve to the curves list - */ -FlatCurveEditor* FlatCurveEditorSubGroup::addCurve(Glib::ustring curveLabel, bool isPeriodic) { - FlatCurveEditor* newCE = new FlatCurveEditor(curveLabel, parent, this, isPeriodic); - - // Initialization of the new curve - storeCurveValues(newCE, getCurveFromGUI(FCT_MinMaxCPoints)); - return newCE; -} - -void FlatCurveEditorSubGroup::showCoordinateAdjuster(CoordinateProvider *provider) { - if (provider == CPointsCurve) { - if (!editPointCPoints->get_active()) editPointCPoints->set_active(true); - } -} - -void FlatCurveEditorSubGroup::stopNumericalAdjustment() { - CPointsCurve->stopNumericalAdjustment(); -} - - -/* - * Force the resize of the curve editor, if the displayed one is the requested one - */ -void FlatCurveEditorSubGroup::refresh(CurveEditor *curveToRefresh) { - if (curveToRefresh != NULL && curveToRefresh == static_cast(parent->displayedCurve)) { - switch(FlatCurveType(curveToRefresh->curveType->getSelected())) { - case (FCT_MinMaxCPoints): - CPointsCurve->refresh(); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } - } -} - -/* - * Switch off the edit button - */ -void FlatCurveEditorSubGroup::editModeSwitchedOff () { - // toggling off all edit buttons, even if only one is toggle on - bool prevState = editCPointsConn.block(true); - editCPoints->set_active(false); - CPointsCurve->pipetteMouseOver(NULL, NULL, 0); - CPointsCurve->setDirty(true); - if (!prevState) editCPointsConn.block(false); -} - -void FlatCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, int modifierKey) { - CurveEditor *curveEditor = static_cast(parent->displayedCurve); - switch((FlatCurveType)(curveEditor->curveType->getSelected())) { - case (FCT_MinMaxCPoints): - CPointsCurve->pipetteMouseOver(curveEditor, provider, modifierKey); - CPointsCurve->setDirty(true); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } -} - -void FlatCurveEditorSubGroup::pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) { - CurveEditor *curveEditor = static_cast(parent->displayedCurve); - switch((FlatCurveType)(curveEditor->curveType->getSelected())) { - case (FCT_MinMaxCPoints): - CPointsCurve->pipetteButton1Pressed(provider, modifierKey); - CPointsCurve->setDirty(true); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } -} - -void FlatCurveEditorSubGroup::pipetteButton1Released(EditDataProvider *provider) { - CurveEditor *curveEditor = static_cast(parent->displayedCurve); - switch((FlatCurveType)(curveEditor->curveType->getSelected())) { - case (FCT_MinMaxCPoints): - CPointsCurve->pipetteButton1Released(provider); - CPointsCurve->setDirty(true); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } -} - -void FlatCurveEditorSubGroup::pipetteDrag(EditDataProvider *provider, int modifierKey) { - CurveEditor *curveEditor = static_cast(parent->displayedCurve); - switch((FlatCurveType)(curveEditor->curveType->getSelected())) { - case (FCT_MinMaxCPoints): - CPointsCurve->pipetteDrag(provider, modifierKey); - CPointsCurve->setDirty(true); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } -} - -/* - * Switch the editor widgets to the currently edited curve - */ -void FlatCurveEditorSubGroup::switchGUI() { - - removeEditor(); - - FlatCurveEditor* dCurve = static_cast(parent->displayedCurve); - - if (dCurve) { - - // Initializing GUI values + repacking the appropriated widget - //dCurve->typeconn.block(true); - - // first we update the colored bar - - ColorProvider *barColorProvider = dCurve->getLeftBarColorProvider(); - std::vector bgGradient = dCurve->getLeftBarBgGradient(); - if (barColorProvider == NULL && bgGradient.size() == 0) { - // dCurve has no left colored bar, so we delete the object - if (leftBar) { - delete leftBar; - leftBar = NULL; - } - } - else { - // dCurve has a ColorProvider or a background gradient defined, so we create/update the object - if (!leftBar) { - leftBar = new ColoredBar(RTO_Bottom2Top); - } - if (barColorProvider) { - bgGradient.clear(); - leftBar->setColorProvider(barColorProvider, dCurve->getLeftBarCallerId()); - leftBar->setBgGradient (bgGradient); - } - else { - leftBar->setColorProvider(NULL, -1); - leftBar->setBgGradient (bgGradient); - } - } - - barColorProvider = dCurve->getBottomBarColorProvider(); - bgGradient = dCurve->getBottomBarBgGradient(); - if (barColorProvider == NULL && bgGradient.size() == 0) { - // dCurve has no bottom colored bar, so we delete the object - if (bottomBar) { - delete bottomBar; - bottomBar = NULL; - } - } - else { - // dCurve ave a ColorProvider or a background gradient defined, so we create/update the object - if (!bottomBar) { - bottomBar = new ColoredBar(RTO_Left2Right); - } - if (barColorProvider) { - bgGradient.clear(); - bottomBar->setColorProvider(barColorProvider, dCurve->getBottomBarCallerId()); - bottomBar->setBgGradient (bgGradient); - } - else { - bottomBar->setColorProvider(NULL, -1); - bottomBar->setBgGradient (bgGradient); - } - } - - switch((FlatCurveType)(dCurve->curveType->getSelected())) { - case (FCT_MinMaxCPoints): - CPointsCurve->setPeriodicity(dCurve->periodic); // Setting Periodicity before setting points - CPointsCurve->setPoints (dCurve->controlPointsCurveEd); - CPointsCurve->setColorProvider(dCurve->getCurveColorProvider(), dCurve->getCurveCallerId()); - CPointsCurve->setColoredBar(leftBar, bottomBar); - CPointsCurve->forceResize(); - updateEditButton(dCurve, editCPoints, editCPointsConn); - parent->pack_start (*CPointsCurveBox); - CPointsCurveBox->check_resize(); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } - - //dCurve->typeconn.block(false); - } -} - -void FlatCurveEditorSubGroup::savePressed () { - - Glib::ustring fname = outputFile(); - if (fname.size()) { - std::ofstream f (fname.c_str()); - std::vector p; - //std::vector p = customCurve->getPoints (); - - switch (parent->displayedCurve->selected) { - case FCT_MinMaxCPoints: // Control points - p = CPointsCurve->getPoints (); - break; - default: - break; - } - - int ix = 0; - if (p[ix]==(double)(FCT_Linear)) - f << "Linear" << std::endl; - else if (p[ix]==(double)(FCT_MinMaxCPoints)) - f << "ControlPoints" << std::endl; - ix++; - for (unsigned int i=0; i p; - std::string s; - f >> s; - if (s=="Linear") - p.push_back ((double)(FCT_Linear)); - else if (s=="ControlPoints") - p.push_back ((double)(FCT_MinMaxCPoints)); - else return; - double x; - while (f) { - f >> x; - if (f) - p.push_back (x); - } - if (p[0] == (double)(FCT_MinMaxCPoints)) { - CPointsCurve->setPoints (p); - CPointsCurve->queue_draw (); - CPointsCurve->notifyListener (); - } - } - } -} - -void FlatCurveEditorSubGroup::copyPressed () { -// For compatibility use enum FlatCurveType here - - std::vector curve; - - switch (parent->displayedCurve->selected) { - case FCT_MinMaxCPoints: // custom - curve = CPointsCurve->getPoints (); - clipboard.setFlatCurveData (curve,FCT_MinMaxCPoints); - break; - default: // (DCT_Linear, DCT_Unchanged) - // ... do nothing - break; - } -} - -void FlatCurveEditorSubGroup::pastePressed () { -// For compatibility use enum FlatCurveType here - - std::vector curve; - FlatCurveType type; - - type = clipboard.hasFlatCurveData(); - - if (type == (FlatCurveType)parent->displayedCurve->selected) { - curve = clipboard.getFlatCurveData (); - switch (type) { - case FCT_MinMaxCPoints: // min/max control points - CPointsCurve->setPoints (curve); - CPointsCurve->queue_draw (); - CPointsCurve->notifyListener (); - break; - default: // (FCT_Linear, FCT_Unchanged) - // ... do nothing - break; - } - } - return; -} - -void FlatCurveEditorSubGroup::editPointToggled(Gtk::ToggleButton *button) { - if (button->get_active()) - CPointsCoordAdjuster->show(); - else { - CPointsCurve->stopNumericalAdjustment(); - CPointsCoordAdjuster->hide(); - } -} - -void FlatCurveEditorSubGroup::editToggled (Gtk::ToggleButton *button) { - FlatCurveEditor* dCurve = static_cast(parent->displayedCurve); - if (!dCurve) - // should never happen! - return; - - if (button->get_active()) { - dCurve->subscribe(); - CPointsCurve->notifyListener (); - - } - else { - dCurve->unsubscribe(); - } -} - - -/* - * Store the curves of the currently displayed type from the widgets to the CurveEditor object - */ -void FlatCurveEditorSubGroup::storeDisplayedCurve() { - if (parent->displayedCurve) { - switch (parent->displayedCurve->selected) { - /*case (FCT_Parametric): - storeCurveValues(parent->displayedCurve, getCurveFromGUI(FCT_Parametric)); - break;*/ - case (FCT_MinMaxCPoints): - storeCurveValues(parent->displayedCurve, getCurveFromGUI(FCT_MinMaxCPoints)); - break; - default: - break; - } - } -} - -/* - * Restore the histogram to all types from the CurveEditor object to the widgets - */ -void FlatCurveEditorSubGroup::restoreDisplayedHistogram() { - if (parent->displayedCurve) { - //paramCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); - CPointsCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); - } - -} - -void FlatCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::vector& p) { - if (!p.empty()) { - FlatCurveType t = static_cast(p[0]); - - switch (t) { - case (FCT_MinMaxCPoints): - static_cast(ce)->controlPointsCurveEd = p; - break; - default: - break; - } - } -} - -/* - * Called to update the parametric curve graph with new slider values - */ -const std::vector FlatCurveEditorSubGroup::getCurveFromGUI (int type) { - switch ((FlatCurveType)type) { - case (FCT_MinMaxCPoints): - return CPointsCurve->getPoints (); - default: { - // linear and other solutions - std::vector lcurve (1); - lcurve[0] = (double)(FCT_Linear); - return lcurve; - } - } -} - -/* - * Unlink the tree editor widgets from their parent box to hide them - */ -void FlatCurveEditorSubGroup::removeEditor () { - removeIfThere (parent, CPointsCurveBox, false); -} - -bool FlatCurveEditorSubGroup::curveReset(CurveEditor *ce) { - if (!ce) - return false; - - FlatCurveEditor *fce = static_cast(ce); - - switch (FlatCurveType(ce->selected)) { - case (FCT_MinMaxCPoints) : // = Control cage - CPointsCurve->reset (fce->controlPointsResetCurve, fce->getIdentityValue()); - return true; - break; - /*case (FCT_Parametric) : - highlights->resetPressed(); - lights->resetPressed(); - darks->resetPressed(); - shadows->resetPressed(); - shcSelector->reset(); - paramCurve->reset (); - return true; - break;*/ - default: - return false; - break; - } - return true; -} - -/*void FlatCurveEditorSubGroup::updateBackgroundHistogram (CurveEditor* ce) { - CurveEditor* fce = (CurveEditor*)ce; - if (fce==displayedCurve) { - paramCurve->updateBackgroundHistogram (fce->bgHistValid ? fce->histogram : NULL); - customCurve->updateBackgroundHistogram (fce->bgHistValid ? fce->histogram : NULL); - NURBSCurve->updateBackgroundHistogram (fce->bgHistValid ? fce->histogram : NULL); - } -}*/ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "clipboard.h" +#include +#include +#include +#include "guiutils.h" +#include "multilangmgr.h" +#include "guiutils.h" +#include "mycurve.h" +#include "shcselector.h" +#include "adjuster.h" +#include "mycurve.h" +#include "myflatcurve.h" +#include "curveeditor.h" +#include "flatcurveeditorsubgroup.h" + +FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::ustring& curveDir) : CurveEditorSubGroup(curveDir) { + + valLinear = (int)FCT_Linear; + valUnchanged = (int)FCT_Unchanged; + parent = prt; + + curveBBoxPos = options.curvebboxpos; + + // ControlPoints curve + CPointsCurveBox = new Gtk::VBox (); + CPointsCurveBox->set_spacing(4); + Gtk::HBox* CPointsCurveAndButtons = Gtk::manage (new Gtk::HBox ()); + CPointsCurveAndButtons->set_spacing(4); + CPointsCurve = Gtk::manage (new MyFlatCurve ()); + CPointsCurve->set_size_request (GRAPH_SIZE+2*RADIUS+1, GRAPH_SIZE+2*RADIUS+1); + CPointsCurve->setType (FCT_MinMaxCPoints); + + Gtk::Box* CPointsbbox; // curvebboxpos 0=above, 1=right, 2=below, 3=left + if (options.curvebboxpos==1 || options.curvebboxpos==3) { + CPointsbbox = Gtk::manage (new Gtk::VBox ()); + } else { + CPointsbbox = Gtk::manage (new Gtk::HBox ()); + } + CPointsbbox->set_spacing(4); + + pasteCPoints = Gtk::manage (new Gtk::Button ()); + pasteCPoints->add (*Gtk::manage (new RTImage ("edit-paste.png"))); + copyCPoints = Gtk::manage (new Gtk::Button ()); + copyCPoints->add (*Gtk::manage (new RTImage ("edit-copy.png"))); + saveCPoints = Gtk::manage (new Gtk::Button ()); + saveCPoints->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); + loadCPoints = Gtk::manage (new Gtk::Button ()); + loadCPoints->add (*Gtk::manage (new RTImage ("gtk-open.png"))); + editCPoints = Gtk::manage (new Gtk::ToggleButton()); + editPointCPoints = Gtk::manage (new Gtk::ToggleButton ()); + editPointCPoints->add (*Gtk::manage (new RTImage ("gtk-edit.png"))); + editPointCPoints->set_tooltip_text(M("CURVEEDITOR_EDITPOINT_HINT")); + editCPoints->add (*Gtk::manage (new RTImage ("editmodehand.png"))); + editCPoints->set_tooltip_text(M("EDIT_PIPETTE_TOOLTIP")); + editCPoints->hide(); + + CPointsbbox->pack_end (*pasteCPoints, Gtk::PACK_SHRINK, 0); + CPointsbbox->pack_end (*copyCPoints, Gtk::PACK_SHRINK, 0); + CPointsbbox->pack_end (*saveCPoints, Gtk::PACK_SHRINK, 0); + CPointsbbox->pack_end (*loadCPoints, Gtk::PACK_SHRINK, 0); + CPointsbbox->pack_start(*editPointCPoints, Gtk::PACK_SHRINK, 0); + CPointsbbox->pack_start(*editCPoints, Gtk::PACK_SHRINK, 0); + + CPointsCurveAndButtons->pack_start (*CPointsCurve, Gtk::PACK_EXPAND_WIDGET, 0); + CPointsCurveAndButtons->pack_start (*CPointsbbox, Gtk::PACK_SHRINK, 0); + CPointsCurveBox->pack_start (*CPointsCurveAndButtons, Gtk::PACK_EXPAND_WIDGET); + if (options.curvebboxpos==0) { + removeIfThere (CPointsCurveAndButtons, CPointsbbox, false); + CPointsCurveBox->pack_start (*CPointsbbox); + CPointsCurveBox->reorder_child(*CPointsbbox, 0); + } else if (options.curvebboxpos==2) { + removeIfThere (CPointsCurveAndButtons, CPointsbbox, false); + CPointsCurveBox->pack_start (*CPointsbbox); + } else if (options.curvebboxpos==3) { + CPointsCurveAndButtons->reorder_child(*CPointsbbox, 0); + } + + { + std::vector axis; + axis.resize(4); + axis.at(0).setValues(M("CURVEEDITOR_AXIS_IN"), 5, 0.001, 0.01, 0., 1.); + axis.at(1).setValues(M("CURVEEDITOR_AXIS_OUT"), 5, 0.001, 0.01, 0., 1.); + axis.at(2).setValues(M("CURVEEDITOR_AXIS_LEFT_TAN"), 5, 0.01, 0.1, 0., 1.); + axis.at(3).setValues(M("CURVEEDITOR_AXIS_RIGHT_TAN"), 5, 0.01, 0.1, 0., 1.); + CPointsCoordAdjuster = Gtk::manage (new CoordinateAdjuster(CPointsCurve, this, axis)); + CPointsCurveBox->pack_start(*CPointsCoordAdjuster, Gtk::PACK_SHRINK, 0); + if (options.curvebboxpos == 2) + CPointsCurveBox->reorder_child(*CPointsCoordAdjuster, 2); + CPointsCoordAdjuster->show_all(); + } + + CPointsCurveBox->show_all (); + CPointsCoordAdjuster->hide(); + + saveCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::savePressed) ); + loadCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::loadPressed) ); + copyCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::copyPressed) ); + pasteCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::pastePressed) ); + editPointCPointsConn = editPointCPoints->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &FlatCurveEditorSubGroup::editPointToggled), editPointCPoints) ); + editCPointsConn = editCPoints->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &FlatCurveEditorSubGroup::editToggled), editCPoints) ); + + saveCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); + loadCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); + copyCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPCOPY")); + pasteCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPPASTE")); + + CPointsCurve->setCurveListener (parent); // Send the message directly to the parent +} + +FlatCurveEditorSubGroup::~FlatCurveEditorSubGroup() { + delete CPointsCurveBox; +} + +/* + * Add a new curve to the curves list + */ +FlatCurveEditor* FlatCurveEditorSubGroup::addCurve(Glib::ustring curveLabel, bool isPeriodic) { + FlatCurveEditor* newCE = new FlatCurveEditor(curveLabel, parent, this, isPeriodic); + + // Initialization of the new curve + storeCurveValues(newCE, getCurveFromGUI(FCT_MinMaxCPoints)); + return newCE; +} + +void FlatCurveEditorSubGroup::showCoordinateAdjuster(CoordinateProvider *provider) { + if (provider == CPointsCurve) { + if (!editPointCPoints->get_active()) editPointCPoints->set_active(true); + } +} + +void FlatCurveEditorSubGroup::stopNumericalAdjustment() { + CPointsCurve->stopNumericalAdjustment(); +} + + +/* + * Force the resize of the curve editor, if the displayed one is the requested one + */ +void FlatCurveEditorSubGroup::refresh(CurveEditor *curveToRefresh) { + if (curveToRefresh != NULL && curveToRefresh == static_cast(parent->displayedCurve)) { + switch(FlatCurveType(curveToRefresh->curveType->getSelected())) { + case (FCT_MinMaxCPoints): + CPointsCurve->refresh(); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } + } +} + +/* + * Switch off the edit button + */ +void FlatCurveEditorSubGroup::editModeSwitchedOff () { + // toggling off all edit buttons, even if only one is toggle on + bool prevState = editCPointsConn.block(true); + editCPoints->set_active(false); + CPointsCurve->pipetteMouseOver(NULL, NULL, 0); + CPointsCurve->setDirty(true); + if (!prevState) editCPointsConn.block(false); +} + +void FlatCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, int modifierKey) { + CurveEditor *curveEditor = static_cast(parent->displayedCurve); + switch((FlatCurveType)(curveEditor->curveType->getSelected())) { + case (FCT_MinMaxCPoints): + CPointsCurve->pipetteMouseOver(curveEditor, provider, modifierKey); + CPointsCurve->setDirty(true); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +void FlatCurveEditorSubGroup::pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) { + CurveEditor *curveEditor = static_cast(parent->displayedCurve); + switch((FlatCurveType)(curveEditor->curveType->getSelected())) { + case (FCT_MinMaxCPoints): + CPointsCurve->pipetteButton1Pressed(provider, modifierKey); + CPointsCurve->setDirty(true); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +void FlatCurveEditorSubGroup::pipetteButton1Released(EditDataProvider *provider) { + CurveEditor *curveEditor = static_cast(parent->displayedCurve); + switch((FlatCurveType)(curveEditor->curveType->getSelected())) { + case (FCT_MinMaxCPoints): + CPointsCurve->pipetteButton1Released(provider); + CPointsCurve->setDirty(true); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +void FlatCurveEditorSubGroup::pipetteDrag(EditDataProvider *provider, int modifierKey) { + CurveEditor *curveEditor = static_cast(parent->displayedCurve); + switch((FlatCurveType)(curveEditor->curveType->getSelected())) { + case (FCT_MinMaxCPoints): + CPointsCurve->pipetteDrag(provider, modifierKey); + CPointsCurve->setDirty(true); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +/* + * Switch the editor widgets to the currently edited curve + */ +void FlatCurveEditorSubGroup::switchGUI() { + + removeEditor(); + + FlatCurveEditor* dCurve = static_cast(parent->displayedCurve); + + if (dCurve) { + + // Initializing GUI values + repacking the appropriated widget + //dCurve->typeconn.block(true); + + // first we update the colored bar + + ColorProvider *barColorProvider = dCurve->getLeftBarColorProvider(); + std::vector bgGradient = dCurve->getLeftBarBgGradient(); + if (barColorProvider == NULL && bgGradient.size() == 0) { + // dCurve has no left colored bar, so we delete the object + if (leftBar) { + delete leftBar; + leftBar = NULL; + } + } + else { + // dCurve has a ColorProvider or a background gradient defined, so we create/update the object + if (!leftBar) { + leftBar = new ColoredBar(RTO_Bottom2Top); + } + if (barColorProvider) { + bgGradient.clear(); + leftBar->setColorProvider(barColorProvider, dCurve->getLeftBarCallerId()); + leftBar->setBgGradient (bgGradient); + } + else { + leftBar->setColorProvider(NULL, -1); + leftBar->setBgGradient (bgGradient); + } + } + + barColorProvider = dCurve->getBottomBarColorProvider(); + bgGradient = dCurve->getBottomBarBgGradient(); + if (barColorProvider == NULL && bgGradient.size() == 0) { + // dCurve has no bottom colored bar, so we delete the object + if (bottomBar) { + delete bottomBar; + bottomBar = NULL; + } + } + else { + // dCurve ave a ColorProvider or a background gradient defined, so we create/update the object + if (!bottomBar) { + bottomBar = new ColoredBar(RTO_Left2Right); + } + if (barColorProvider) { + bgGradient.clear(); + bottomBar->setColorProvider(barColorProvider, dCurve->getBottomBarCallerId()); + bottomBar->setBgGradient (bgGradient); + } + else { + bottomBar->setColorProvider(NULL, -1); + bottomBar->setBgGradient (bgGradient); + } + } + + switch((FlatCurveType)(dCurve->curveType->getSelected())) { + case (FCT_MinMaxCPoints): + CPointsCurve->setPeriodicity(dCurve->periodic); // Setting Periodicity before setting points + CPointsCurve->setPoints (dCurve->controlPointsCurveEd); + CPointsCurve->setColorProvider(dCurve->getCurveColorProvider(), dCurve->getCurveCallerId()); + CPointsCurve->setColoredBar(leftBar, bottomBar); + CPointsCurve->forceResize(); + updateEditButton(dCurve, editCPoints, editCPointsConn); + parent->pack_start (*CPointsCurveBox); + CPointsCurveBox->check_resize(); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } + + //dCurve->typeconn.block(false); + } +} + +void FlatCurveEditorSubGroup::savePressed () { + + Glib::ustring fname = outputFile(); + if (fname.size()) { + std::ofstream f (fname.c_str()); + std::vector p; + //std::vector p = customCurve->getPoints (); + + switch (parent->displayedCurve->selected) { + case FCT_MinMaxCPoints: // Control points + p = CPointsCurve->getPoints (); + break; + default: + break; + } + + int ix = 0; + if (p[ix]==(double)(FCT_Linear)) + f << "Linear" << std::endl; + else if (p[ix]==(double)(FCT_MinMaxCPoints)) + f << "ControlPoints" << std::endl; + ix++; + for (unsigned int i=0; i p; + std::string s; + f >> s; + if (s=="Linear") + p.push_back ((double)(FCT_Linear)); + else if (s=="ControlPoints") + p.push_back ((double)(FCT_MinMaxCPoints)); + else return; + double x; + while (f) { + f >> x; + if (f) + p.push_back (x); + } + if (p[0] == (double)(FCT_MinMaxCPoints)) { + CPointsCurve->setPoints (p); + CPointsCurve->queue_draw (); + CPointsCurve->notifyListener (); + } + } + } +} + +void FlatCurveEditorSubGroup::copyPressed () { +// For compatibility use enum FlatCurveType here + + std::vector curve; + + switch (parent->displayedCurve->selected) { + case FCT_MinMaxCPoints: // custom + curve = CPointsCurve->getPoints (); + clipboard.setFlatCurveData (curve,FCT_MinMaxCPoints); + break; + default: // (DCT_Linear, DCT_Unchanged) + // ... do nothing + break; + } +} + +void FlatCurveEditorSubGroup::pastePressed () { +// For compatibility use enum FlatCurveType here + + std::vector curve; + FlatCurveType type; + + type = clipboard.hasFlatCurveData(); + + if (type == (FlatCurveType)parent->displayedCurve->selected) { + curve = clipboard.getFlatCurveData (); + switch (type) { + case FCT_MinMaxCPoints: // min/max control points + CPointsCurve->setPoints (curve); + CPointsCurve->queue_draw (); + CPointsCurve->notifyListener (); + break; + default: // (FCT_Linear, FCT_Unchanged) + // ... do nothing + break; + } + } + return; +} + +void FlatCurveEditorSubGroup::editPointToggled(Gtk::ToggleButton *button) { + if (button->get_active()) + CPointsCoordAdjuster->show(); + else { + CPointsCurve->stopNumericalAdjustment(); + CPointsCoordAdjuster->hide(); + } +} + +void FlatCurveEditorSubGroup::editToggled (Gtk::ToggleButton *button) { + FlatCurveEditor* dCurve = static_cast(parent->displayedCurve); + if (!dCurve) + // should never happen! + return; + + if (button->get_active()) { + dCurve->subscribe(); + CPointsCurve->notifyListener (); + + } + else { + dCurve->unsubscribe(); + } +} + + +/* + * Store the curves of the currently displayed type from the widgets to the CurveEditor object + */ +void FlatCurveEditorSubGroup::storeDisplayedCurve() { + if (parent->displayedCurve) { + switch (parent->displayedCurve->selected) { + /*case (FCT_Parametric): + storeCurveValues(parent->displayedCurve, getCurveFromGUI(FCT_Parametric)); + break;*/ + case (FCT_MinMaxCPoints): + storeCurveValues(parent->displayedCurve, getCurveFromGUI(FCT_MinMaxCPoints)); + break; + default: + break; + } + } +} + +/* + * Restore the histogram to all types from the CurveEditor object to the widgets + */ +void FlatCurveEditorSubGroup::restoreDisplayedHistogram() { + if (parent->displayedCurve) { + //paramCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); + CPointsCurve->updateBackgroundHistogram (parent->displayedCurve->histogram); + } + +} + +void FlatCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::vector& p) { + if (!p.empty()) { + FlatCurveType t = static_cast(p[0]); + + switch (t) { + case (FCT_MinMaxCPoints): + static_cast(ce)->controlPointsCurveEd = p; + break; + default: + break; + } + } +} + +/* + * Called to update the parametric curve graph with new slider values + */ +const std::vector FlatCurveEditorSubGroup::getCurveFromGUI (int type) { + switch ((FlatCurveType)type) { + case (FCT_MinMaxCPoints): + return CPointsCurve->getPoints (); + default: { + // linear and other solutions + std::vector lcurve (1); + lcurve[0] = (double)(FCT_Linear); + return lcurve; + } + } +} + +/* + * Unlink the tree editor widgets from their parent box to hide them + */ +void FlatCurveEditorSubGroup::removeEditor () { + removeIfThere (parent, CPointsCurveBox, false); +} + +bool FlatCurveEditorSubGroup::curveReset(CurveEditor *ce) { + if (!ce) + return false; + + FlatCurveEditor *fce = static_cast(ce); + + switch (FlatCurveType(ce->selected)) { + case (FCT_MinMaxCPoints) : // = Control cage + CPointsCurve->reset (fce->controlPointsResetCurve, fce->getIdentityValue()); + return true; + break; + /*case (FCT_Parametric) : + highlights->resetPressed(); + lights->resetPressed(); + darks->resetPressed(); + shadows->resetPressed(); + shcSelector->reset(); + paramCurve->reset (); + return true; + break;*/ + default: + return false; + break; + } + return true; +} + +/*void FlatCurveEditorSubGroup::updateBackgroundHistogram (CurveEditor* ce) { + CurveEditor* fce = (CurveEditor*)ce; + if (fce==displayedCurve) { + paramCurve->updateBackgroundHistogram (fce->bgHistValid ? fce->histogram : NULL); + customCurve->updateBackgroundHistogram (fce->bgHistValid ? fce->histogram : NULL); + NURBSCurve->updateBackgroundHistogram (fce->bgHistValid ? fce->histogram : NULL); + } +}*/ diff --git a/rtgui/flatcurveeditorsubgroup.h b/rtgui/flatcurveeditorsubgroup.h index e937dd362..a5b2c9cb5 100644 --- a/rtgui/flatcurveeditorsubgroup.h +++ b/rtgui/flatcurveeditorsubgroup.h @@ -1,78 +1,78 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _FLATCURVEEDITORSUBGROUP_ -#define _FLATCURVEEDITORSUBGROUP_ - -#include -#include "curveeditorgroup.h" - -class FlatCurveEditor; - -class FlatCurveEditorSubGroup: public CurveEditorSubGroup { - - friend class FlatCurveEditor; - -protected: - Gtk::VBox* CPointsCurveBox; - - MyFlatCurve* CPointsCurve; - - CoordinateAdjuster *CPointsCoordAdjuster; - - Gtk::Button* saveCPoints; - Gtk::Button* loadCPoints; - Gtk::Button* copyCPoints; - Gtk::Button* pasteCPoints; - Gtk::ToggleButton* editPointCPoints; - Gtk::ToggleButton* editCPoints; - sigc::connection editCPointsConn, editPointCPointsConn; - -public: - FlatCurveEditorSubGroup(CurveEditorGroup* prt, Glib::ustring& curveDir); - virtual ~FlatCurveEditorSubGroup(); - - FlatCurveEditor* addCurve(Glib::ustring curveLabel = "", bool periodic = true); - //virtual void updateBackgroundHistogram (CurveEditor* ce); - void switchGUI(); - void refresh(CurveEditor *curveToRefresh); - void editModeSwitchedOff(); - void pipetteMouseOver(EditDataProvider *provider, int modifierKey); - void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey); - void pipetteButton1Released(EditDataProvider *provider); - void pipetteDrag(EditDataProvider *provider, int modifierKey); - void showCoordinateAdjuster(CoordinateProvider *provider); - void stopNumericalAdjustment(); - - bool curveReset (CurveEditor *ce); - -protected: - void storeCurveValues (CurveEditor* ce, const std::vector& p); - void storeDisplayedCurve (); - void restoreDisplayedHistogram (); - void savePressed (); - void loadPressed (); - void copyPressed (); - void pastePressed (); - void removeEditor (); - const std::vector getCurveFromGUI (int type); - void editPointToggled(Gtk::ToggleButton *button); - void editToggled (Gtk::ToggleButton *button); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _FLATCURVEEDITORSUBGROUP_ +#define _FLATCURVEEDITORSUBGROUP_ + +#include +#include "curveeditorgroup.h" + +class FlatCurveEditor; + +class FlatCurveEditorSubGroup: public CurveEditorSubGroup { + + friend class FlatCurveEditor; + +protected: + Gtk::VBox* CPointsCurveBox; + + MyFlatCurve* CPointsCurve; + + CoordinateAdjuster *CPointsCoordAdjuster; + + Gtk::Button* saveCPoints; + Gtk::Button* loadCPoints; + Gtk::Button* copyCPoints; + Gtk::Button* pasteCPoints; + Gtk::ToggleButton* editPointCPoints; + Gtk::ToggleButton* editCPoints; + sigc::connection editCPointsConn, editPointCPointsConn; + +public: + FlatCurveEditorSubGroup(CurveEditorGroup* prt, Glib::ustring& curveDir); + virtual ~FlatCurveEditorSubGroup(); + + FlatCurveEditor* addCurve(Glib::ustring curveLabel = "", bool periodic = true); + //virtual void updateBackgroundHistogram (CurveEditor* ce); + void switchGUI(); + void refresh(CurveEditor *curveToRefresh); + void editModeSwitchedOff(); + void pipetteMouseOver(EditDataProvider *provider, int modifierKey); + void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey); + void pipetteButton1Released(EditDataProvider *provider); + void pipetteDrag(EditDataProvider *provider, int modifierKey); + void showCoordinateAdjuster(CoordinateProvider *provider); + void stopNumericalAdjustment(); + + bool curveReset (CurveEditor *ce); + +protected: + void storeCurveValues (CurveEditor* ce, const std::vector& p); + void storeDisplayedCurve (); + void restoreDisplayedHistogram (); + void savePressed (); + void loadPressed (); + void copyPressed (); + void pastePressed (); + void removeEditor (); + const std::vector getCurveFromGUI (int type); + void editPointToggled(Gtk::ToggleButton *button); + void editToggled (Gtk::ToggleButton *button); +}; + +#endif diff --git a/rtgui/flatfield.cc b/rtgui/flatfield.cc index 901090aea..81f3421b6 100644 --- a/rtgui/flatfield.cc +++ b/rtgui/flatfield.cc @@ -1,380 +1,380 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "flatfield.h" -#include "options.h" -#include "guiutils.h" -#include "../rtengine/safegtk.h" -#include -#include "rtimage.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_LABEL")) -{ - hbff = Gtk::manage(new Gtk::HBox()); - hbff->set_spacing(2); - flatFieldFile = Gtk::manage(new MyFileChooserButton(M("TP_FLATFIELD_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); - flatFieldFilePersister.reset(new FileChooserLastFolderPersister(flatFieldFile, options.lastFlatfieldDir)); - ffLabel = Gtk::manage(new Gtk::Label(M("GENERAL_FILE"))); - flatFieldFileReset = Gtk::manage(new Gtk::Button()); - flatFieldFileReset->set_image (*Gtk::manage(new RTImage ("gtk-cancel.png"))); - hbff->pack_start(*ffLabel, Gtk::PACK_SHRINK, 0); - hbff->pack_start(*flatFieldFile); - hbff->pack_start(*flatFieldFileReset, Gtk::PACK_SHRINK, 0); - flatFieldAutoSelect = Gtk::manage(new Gtk::CheckButton((M("TP_FLATFIELD_AUTOSELECT")))); - ffInfo = Gtk::manage(new Gtk::Label("")); - ffInfo->set_alignment(0,0); //left align - flatFieldBlurRadius = Gtk::manage(new Adjuster (M("TP_FLATFIELD_BLURRADIUS"),0,200,2,32)); - flatFieldBlurRadius->setAdjusterListener (this); - if (flatFieldBlurRadius->delay < 1000) flatFieldBlurRadius->delay = 1000; - flatFieldBlurRadius->show(); - - Gtk::HBox* hbffbt = Gtk::manage (new Gtk::HBox ()); - hbffbt->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_FLATFIELD_BLURTYPE") +":"))); - hbffbt->set_spacing(4); - flatFieldBlurType = Gtk::manage (new MyComboBoxText ()); - flatFieldBlurType->append_text(M("TP_FLATFIELD_BT_AREA")); - flatFieldBlurType->append_text(M("TP_FLATFIELD_BT_VERTICAL")); - flatFieldBlurType->append_text(M("TP_FLATFIELD_BT_HORIZONTAL")); - flatFieldBlurType->append_text(M("TP_FLATFIELD_BT_VERTHORIZ")); - flatFieldBlurType->set_active(0); - hbffbt->pack_end (*flatFieldBlurType); - - flatFieldClipControl = Gtk::manage (new Adjuster(M("TP_FLATFIELD_CLIPCONTROL"), 0., 100., 1., 0.)); - flatFieldClipControl->setAdjusterListener(this); - flatFieldClipControl->addAutoButton(""); - if (flatFieldClipControl->delay < 1000) flatFieldClipControl->delay = 1000; - flatFieldClipControl->show(); - flatFieldClipControl->set_tooltip_markup (M("TP_FLATFIELD_CLIPCONTROL_TOOLTIP")); - - pack_start( *hbff, Gtk::PACK_SHRINK, 0); - pack_start( *flatFieldAutoSelect, Gtk::PACK_SHRINK, 0); - pack_start( *ffInfo, Gtk::PACK_SHRINK, 0); - pack_start( *hbffbt, Gtk::PACK_SHRINK, 0); - pack_start( *flatFieldBlurRadius, Gtk::PACK_SHRINK, 0); - pack_start( *flatFieldClipControl, Gtk::PACK_SHRINK, 0); - - flatFieldFileconn = flatFieldFile->signal_file_set().connect ( sigc::mem_fun(*this, &FlatField::flatFieldFileChanged), true); - flatFieldFileReset->signal_clicked().connect( sigc::mem_fun(*this, &FlatField::flatFieldFile_Reset), true ); - flatFieldAutoSelectconn = flatFieldAutoSelect->signal_toggled().connect ( sigc::mem_fun(*this, &FlatField::flatFieldAutoSelectChanged), true); - flatFieldBlurTypeconn = flatFieldBlurType->signal_changed().connect( sigc::mem_fun(*this, &FlatField::flatFieldBlurTypeChanged) ); - lastShortcutPath = ""; - - // Set filename filters - b_filter_asCurrent = false; - Gtk::FileFilter *filter_any = Gtk::manage(new Gtk::FileFilter); - filter_any->add_pattern("*"); - filter_any->set_name(M("FILECHOOSER_FILTER_ANY")); - flatFieldFile->add_filter (*filter_any); - - // filters for all supported non-raw extensions - for (size_t i=0; iadd_pattern("*." + options.parseExtensions[i]); - filter_ff->add_pattern("*." + options.parseExtensions[i].uppercase()); - filter_ff->set_name(options.parseExtensions[i].uppercase()); - flatFieldFile->add_filter (*filter_ff); - //printf("adding filter %s \n",options.parseExtensions[i].uppercase().c_str()); - } - } -} - -void FlatField::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - flatFieldAutoSelectconn.block (true); - flatFieldBlurTypeconn.block (true); - - //flatFieldBlurType - for( size_t i=0; i< procparams::RAWParams::numFlatFileBlurTypes;i++) - if( pp->raw.ff_BlurType == procparams::RAWParams::ff_BlurTypestring[i]){ - flatFieldBlurType->set_active(i); - break; - } - - if (multiImage || pp->raw.ff_BlurType == procparams::RAWParams::ff_BlurTypestring[procparams::RAWParams::area_ff]) - flatFieldClipControl->show(); - else - flatFieldClipControl->hide(); - - flatFieldAutoSelect->set_active (pp->raw.ff_AutoSelect); - flatFieldBlurRadius->setValue (pp->raw.ff_BlurRadius); - flatFieldClipControl->setValue (pp->raw.ff_clipControl); - flatFieldClipControl->setAutoValue (pp->raw.ff_AutoClipControl); - - if(pedited ){ - flatFieldAutoSelect->set_inconsistent (!pedited->raw.ff_AutoSelect); - flatFieldBlurRadius->setEditedState( pedited->raw.ff_BlurRadius ? Edited : UnEdited ); - flatFieldClipControl->setEditedState( pedited->raw.ff_clipControl ? Edited : UnEdited ); - flatFieldClipControl->setAutoInconsistent(multiImage && !pedited->raw.ff_AutoClipControl); - if( !pedited->raw.ff_BlurType ) - flatFieldBlurType->set_active(procparams::RAWParams::numFlatFileBlurTypes); // No name - } - if (safe_file_test (pp->raw.ff_file, Glib::FILE_TEST_EXISTS)) - flatFieldFile->set_filename (pp->raw.ff_file); - else - flatFieldFile_Reset(); - hbff->set_sensitive( !pp->raw.ff_AutoSelect ); - - lastFFAutoSelect = pp->raw.ff_AutoSelect; - lastFFAutoClipCtrl = pp->raw.ff_AutoClipControl; - - if( pp->raw.ff_AutoSelect && ffp && !batchMode){ - // retrieve the auto-selected ff filename - rtengine::RawImage *img = ffp->getFF(); - if( img ){ - ffInfo->set_text( Glib::ustring::compose("%1: f/%2", Glib::path_get_basename(img->get_filename()), img->get_aperture()) ); // !!! need to add focallength in mm and format aperture to ##.# - }else{ - ffInfo->set_text(Glib::ustring(M("TP_PREPROCESS_NO_FOUND"))); - } - } - else ffInfo->set_text(""); - - ffChanged = false; - - flatFieldAutoSelectconn.block (false); - flatFieldBlurTypeconn.block (false); - enableListener (); - - // Add filter with the current file extension if the current file is raw - if (ffp && !batchMode){ - - if (b_filter_asCurrent){ - //First, remove last filter_asCurrent if it was set for a raw file - std::vector filters = flatFieldFile->list_filters(); - flatFieldFile->remove_filter(**(filters.end()-1)); - b_filter_asCurrent = false; - } - - Glib::ustring fname = Glib::path_get_basename(ffp->GetCurrentImageFilePath()); - Glib::ustring filetype; - - if (fname!=""){ - // get image filetype, set filter to the same as current image's filetype - std::string::size_type idx; - idx = fname.rfind('.'); - if(idx != std::string::npos){ - filetype = fname.substr(idx+1); - //exclude non-raw - israw = filetype.uppercase()!="JPG" && filetype.uppercase()!="JPEG" && filetype.uppercase()!="PNG" && filetype.uppercase()!="TIF" && filetype.uppercase()!="TIFF"; - - if (israw) - { - b_filter_asCurrent = true; //prevent re-adding this filter on every pp3 file read - Gtk::FileFilter *filter_asCurrent = Gtk::manage(new Gtk::FileFilter); - filter_asCurrent->add_pattern("*." + filetype); - filter_asCurrent->set_name(M("FILECHOOSER_FILTER_SAME") + " (" + filetype + ")"); - flatFieldFile->add_filter (*filter_asCurrent); - flatFieldFile->set_filter (*filter_asCurrent); - } - } - } - } - -} - -void FlatField::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.ff_file = flatFieldFile->get_filename(); - pp->raw.ff_AutoSelect = flatFieldAutoSelect->get_active(); - pp->raw.ff_BlurRadius = flatFieldBlurRadius->getIntValue(); - pp->raw.ff_clipControl = flatFieldClipControl->getIntValue(); - pp->raw.ff_AutoClipControl = flatFieldClipControl->getAutoValue(); - - int currentRow = flatFieldBlurType->get_active_row_number(); - if( currentRow>=0 && currentRow < procparams::RAWParams::numFlatFileBlurTypes) - pp->raw.ff_BlurType = procparams::RAWParams::ff_BlurTypestring[currentRow]; - - if (pedited) { - pedited->raw.ff_file = ffChanged; - pedited->raw.ff_AutoSelect = !flatFieldAutoSelect->get_inconsistent(); - pedited->raw.ff_BlurRadius = flatFieldBlurRadius->getEditedState (); - pedited->raw.ff_clipControl = flatFieldClipControl->getEditedState (); - pedited->raw.ff_AutoClipControl = !flatFieldClipControl->getAutoInconsistent(); - pedited->raw.ff_BlurType = flatFieldBlurType->get_active_row_number() != procparams::RAWParams::numFlatFileBlurTypes; - } - -} - -void FlatField::adjusterChanged (Adjuster* a, double newval) -{ - if (listener) { - - Glib::ustring value = a->getTextValue(); - - if (a==flatFieldBlurRadius) - listener->panelChanged (EvFlatFieldBlurRadius, value); - else if (a==flatFieldClipControl) - listener->panelChanged (EvFlatFieldClipControl, value); - } -} - -void FlatField::adjusterAutoToggled (Adjuster* a, bool newval) { - - if (multiImage) { - if (flatFieldClipControl->getAutoInconsistent()) { - flatFieldClipControl->setAutoInconsistent(false); - flatFieldClipControl->setAutoValue(false); - } - else if (lastFFAutoClipCtrl) - flatFieldClipControl->setAutoInconsistent(true); - - lastFFAutoClipCtrl = flatFieldClipControl->getAutoValue(); - - } - - if (listener) { - if(a==flatFieldClipControl) { - if (flatFieldClipControl->getAutoInconsistent()) - listener->panelChanged (EvFlatFieldAutoClipControl, M("GENERAL_UNCHANGED")); - else if (flatFieldClipControl->getAutoValue()) - listener->panelChanged (EvFlatFieldAutoClipControl, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvFlatFieldAutoClipControl, M("GENERAL_DISABLED")); - } - } -} - -void FlatField::setBatchMode(bool batchMode) -{ - ToolPanel::setBatchMode (batchMode); - flatFieldBlurRadius->showEditedCB (); - flatFieldClipControl->showEditedCB (); -} - -void FlatField::setAdjusterBehavior (bool clipctrladd) { - flatFieldClipControl->setAddMode(clipctrladd); -} - -void FlatField::trimValues (rtengine::procparams::ProcParams* pp) { - flatFieldClipControl->trimValue(pp->raw.ff_clipControl); -} - -void FlatField::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) -{ - flatFieldBlurRadius->setDefault( defParams->raw.ff_BlurRadius); - flatFieldClipControl->setDefault( defParams->raw.ff_clipControl); - - if (pedited) { - flatFieldBlurRadius->setDefaultEditedState( pedited->raw.ff_BlurRadius ? Edited : UnEdited); - flatFieldClipControl->setDefaultEditedState( pedited->raw.ff_clipControl ? Edited : UnEdited); - } else { - flatFieldBlurRadius->setDefaultEditedState( Irrelevant ); - flatFieldClipControl->setDefaultEditedState( Irrelevant ); - } -} - -void FlatField::flatFieldFileChanged() -{ - ffChanged=true; - if (listener) - listener->panelChanged (EvFlatFieldFile, Glib::path_get_basename(flatFieldFile->get_filename())); -} - -void FlatField::flatFieldFile_Reset() -{ - ffChanged=true; - -// caution: I had to make this hack, because set_current_folder() doesn't work correctly! -// Because szeva doesn't exist since he was committed to happy hunting ground in Issue 316 -// we can use him now for this hack - flatFieldFile->set_filename (options.lastFlatfieldDir + "/szeva"); -// end of the hack - - if (!options.lastFlatfieldDir.empty()) - flatFieldFile->set_current_folder(options.lastFlatfieldDir); - - ffInfo->set_text(""); - if (listener) - listener->panelChanged (EvFlatFieldFile, M("GENERAL_NONE") ); -} - -void FlatField::flatFieldBlurTypeChanged () -{ - int curSelection = flatFieldBlurType->get_active_row_number(); - - Glib::ustring s=""; - if( curSelection>=0 && curSelection < procparams::RAWParams::numFlatFileBlurTypes) - s = flatFieldBlurType->get_active_text(); - - if (multiImage || curSelection == procparams::RAWParams::area_ff) - flatFieldClipControl->show(); - else - flatFieldClipControl->hide(); - - if (listener) - listener->panelChanged (EvFlatFieldBlurType, s); -} - -void FlatField::flatFieldAutoSelectChanged() -{ - if (batchMode) { - if (flatFieldAutoSelect->get_inconsistent()) { - flatFieldAutoSelect->set_inconsistent (false); - flatFieldAutoSelectconn.block (true); - flatFieldAutoSelect->set_active (false); - flatFieldAutoSelectconn.block (false); - } - else if (lastFFAutoSelect) - flatFieldAutoSelect->set_inconsistent (true); - - lastFFAutoSelect = flatFieldAutoSelect->get_active (); - } - hbff->set_sensitive( !flatFieldAutoSelect->get_active() ); - - if( flatFieldAutoSelect->get_active() && ffp && !batchMode){ - // retrieve the auto-selected ff filename - rtengine::RawImage *img = ffp->getFF(); - if( img ){ - ffInfo->set_text( Glib::ustring::compose("%1: f/%2", Glib::path_get_basename(img->get_filename()), img->get_aperture()) ); // !!! need to add focallength in mm and format aperture to ##.# - }else{ - ffInfo->set_text(Glib::ustring(M("TP_PREPROCESS_NO_FOUND"))); - } - } - else{ffInfo->set_text("");} - - if (listener) - listener->panelChanged (EvFlatFieldAutoSelect, flatFieldAutoSelect->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); - -} - -void FlatField::setShortcutPath(Glib::ustring path) -{ - if (path == "") return; -#ifdef WIN32 - // Dirty workaround, waiting for a clean solution by using exceptions! - if (!safe_is_shortcut_dir(path)) -#endif - { - if (lastShortcutPath != "") { - try { - flatFieldFile->remove_shortcut_folder(lastShortcutPath); - } - catch (Glib::Error &err) {} - } - lastShortcutPath = path; - try { - flatFieldFile->add_shortcut_folder(path); - } - catch (Glib::Error &err) {} - } -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "flatfield.h" +#include "options.h" +#include "guiutils.h" +#include "../rtengine/safegtk.h" +#include +#include "rtimage.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_LABEL")) +{ + hbff = Gtk::manage(new Gtk::HBox()); + hbff->set_spacing(2); + flatFieldFile = Gtk::manage(new MyFileChooserButton(M("TP_FLATFIELD_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); + flatFieldFilePersister.reset(new FileChooserLastFolderPersister(flatFieldFile, options.lastFlatfieldDir)); + ffLabel = Gtk::manage(new Gtk::Label(M("GENERAL_FILE"))); + flatFieldFileReset = Gtk::manage(new Gtk::Button()); + flatFieldFileReset->set_image (*Gtk::manage(new RTImage ("gtk-cancel.png"))); + hbff->pack_start(*ffLabel, Gtk::PACK_SHRINK, 0); + hbff->pack_start(*flatFieldFile); + hbff->pack_start(*flatFieldFileReset, Gtk::PACK_SHRINK, 0); + flatFieldAutoSelect = Gtk::manage(new Gtk::CheckButton((M("TP_FLATFIELD_AUTOSELECT")))); + ffInfo = Gtk::manage(new Gtk::Label("")); + ffInfo->set_alignment(0,0); //left align + flatFieldBlurRadius = Gtk::manage(new Adjuster (M("TP_FLATFIELD_BLURRADIUS"),0,200,2,32)); + flatFieldBlurRadius->setAdjusterListener (this); + if (flatFieldBlurRadius->delay < 1000) flatFieldBlurRadius->delay = 1000; + flatFieldBlurRadius->show(); + + Gtk::HBox* hbffbt = Gtk::manage (new Gtk::HBox ()); + hbffbt->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_FLATFIELD_BLURTYPE") +":"))); + hbffbt->set_spacing(4); + flatFieldBlurType = Gtk::manage (new MyComboBoxText ()); + flatFieldBlurType->append_text(M("TP_FLATFIELD_BT_AREA")); + flatFieldBlurType->append_text(M("TP_FLATFIELD_BT_VERTICAL")); + flatFieldBlurType->append_text(M("TP_FLATFIELD_BT_HORIZONTAL")); + flatFieldBlurType->append_text(M("TP_FLATFIELD_BT_VERTHORIZ")); + flatFieldBlurType->set_active(0); + hbffbt->pack_end (*flatFieldBlurType); + + flatFieldClipControl = Gtk::manage (new Adjuster(M("TP_FLATFIELD_CLIPCONTROL"), 0., 100., 1., 0.)); + flatFieldClipControl->setAdjusterListener(this); + flatFieldClipControl->addAutoButton(""); + if (flatFieldClipControl->delay < 1000) flatFieldClipControl->delay = 1000; + flatFieldClipControl->show(); + flatFieldClipControl->set_tooltip_markup (M("TP_FLATFIELD_CLIPCONTROL_TOOLTIP")); + + pack_start( *hbff, Gtk::PACK_SHRINK, 0); + pack_start( *flatFieldAutoSelect, Gtk::PACK_SHRINK, 0); + pack_start( *ffInfo, Gtk::PACK_SHRINK, 0); + pack_start( *hbffbt, Gtk::PACK_SHRINK, 0); + pack_start( *flatFieldBlurRadius, Gtk::PACK_SHRINK, 0); + pack_start( *flatFieldClipControl, Gtk::PACK_SHRINK, 0); + + flatFieldFileconn = flatFieldFile->signal_file_set().connect ( sigc::mem_fun(*this, &FlatField::flatFieldFileChanged), true); + flatFieldFileReset->signal_clicked().connect( sigc::mem_fun(*this, &FlatField::flatFieldFile_Reset), true ); + flatFieldAutoSelectconn = flatFieldAutoSelect->signal_toggled().connect ( sigc::mem_fun(*this, &FlatField::flatFieldAutoSelectChanged), true); + flatFieldBlurTypeconn = flatFieldBlurType->signal_changed().connect( sigc::mem_fun(*this, &FlatField::flatFieldBlurTypeChanged) ); + lastShortcutPath = ""; + + // Set filename filters + b_filter_asCurrent = false; + Gtk::FileFilter *filter_any = Gtk::manage(new Gtk::FileFilter); + filter_any->add_pattern("*"); + filter_any->set_name(M("FILECHOOSER_FILTER_ANY")); + flatFieldFile->add_filter (*filter_any); + + // filters for all supported non-raw extensions + for (size_t i=0; iadd_pattern("*." + options.parseExtensions[i]); + filter_ff->add_pattern("*." + options.parseExtensions[i].uppercase()); + filter_ff->set_name(options.parseExtensions[i].uppercase()); + flatFieldFile->add_filter (*filter_ff); + //printf("adding filter %s \n",options.parseExtensions[i].uppercase().c_str()); + } + } +} + +void FlatField::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + flatFieldAutoSelectconn.block (true); + flatFieldBlurTypeconn.block (true); + + //flatFieldBlurType + for( size_t i=0; i< procparams::RAWParams::numFlatFileBlurTypes;i++) + if( pp->raw.ff_BlurType == procparams::RAWParams::ff_BlurTypestring[i]){ + flatFieldBlurType->set_active(i); + break; + } + + if (multiImage || pp->raw.ff_BlurType == procparams::RAWParams::ff_BlurTypestring[procparams::RAWParams::area_ff]) + flatFieldClipControl->show(); + else + flatFieldClipControl->hide(); + + flatFieldAutoSelect->set_active (pp->raw.ff_AutoSelect); + flatFieldBlurRadius->setValue (pp->raw.ff_BlurRadius); + flatFieldClipControl->setValue (pp->raw.ff_clipControl); + flatFieldClipControl->setAutoValue (pp->raw.ff_AutoClipControl); + + if(pedited ){ + flatFieldAutoSelect->set_inconsistent (!pedited->raw.ff_AutoSelect); + flatFieldBlurRadius->setEditedState( pedited->raw.ff_BlurRadius ? Edited : UnEdited ); + flatFieldClipControl->setEditedState( pedited->raw.ff_clipControl ? Edited : UnEdited ); + flatFieldClipControl->setAutoInconsistent(multiImage && !pedited->raw.ff_AutoClipControl); + if( !pedited->raw.ff_BlurType ) + flatFieldBlurType->set_active(procparams::RAWParams::numFlatFileBlurTypes); // No name + } + if (safe_file_test (pp->raw.ff_file, Glib::FILE_TEST_EXISTS)) + flatFieldFile->set_filename (pp->raw.ff_file); + else + flatFieldFile_Reset(); + hbff->set_sensitive( !pp->raw.ff_AutoSelect ); + + lastFFAutoSelect = pp->raw.ff_AutoSelect; + lastFFAutoClipCtrl = pp->raw.ff_AutoClipControl; + + if( pp->raw.ff_AutoSelect && ffp && !batchMode){ + // retrieve the auto-selected ff filename + rtengine::RawImage *img = ffp->getFF(); + if( img ){ + ffInfo->set_text( Glib::ustring::compose("%1: f/%2", Glib::path_get_basename(img->get_filename()), img->get_aperture()) ); // !!! need to add focallength in mm and format aperture to ##.# + }else{ + ffInfo->set_text(Glib::ustring(M("TP_PREPROCESS_NO_FOUND"))); + } + } + else ffInfo->set_text(""); + + ffChanged = false; + + flatFieldAutoSelectconn.block (false); + flatFieldBlurTypeconn.block (false); + enableListener (); + + // Add filter with the current file extension if the current file is raw + if (ffp && !batchMode){ + + if (b_filter_asCurrent){ + //First, remove last filter_asCurrent if it was set for a raw file + std::vector filters = flatFieldFile->list_filters(); + flatFieldFile->remove_filter(**(filters.end()-1)); + b_filter_asCurrent = false; + } + + Glib::ustring fname = Glib::path_get_basename(ffp->GetCurrentImageFilePath()); + Glib::ustring filetype; + + if (fname!=""){ + // get image filetype, set filter to the same as current image's filetype + std::string::size_type idx; + idx = fname.rfind('.'); + if(idx != std::string::npos){ + filetype = fname.substr(idx+1); + //exclude non-raw + israw = filetype.uppercase()!="JPG" && filetype.uppercase()!="JPEG" && filetype.uppercase()!="PNG" && filetype.uppercase()!="TIF" && filetype.uppercase()!="TIFF"; + + if (israw) + { + b_filter_asCurrent = true; //prevent re-adding this filter on every pp3 file read + Gtk::FileFilter *filter_asCurrent = Gtk::manage(new Gtk::FileFilter); + filter_asCurrent->add_pattern("*." + filetype); + filter_asCurrent->set_name(M("FILECHOOSER_FILTER_SAME") + " (" + filetype + ")"); + flatFieldFile->add_filter (*filter_asCurrent); + flatFieldFile->set_filter (*filter_asCurrent); + } + } + } + } + +} + +void FlatField::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.ff_file = flatFieldFile->get_filename(); + pp->raw.ff_AutoSelect = flatFieldAutoSelect->get_active(); + pp->raw.ff_BlurRadius = flatFieldBlurRadius->getIntValue(); + pp->raw.ff_clipControl = flatFieldClipControl->getIntValue(); + pp->raw.ff_AutoClipControl = flatFieldClipControl->getAutoValue(); + + int currentRow = flatFieldBlurType->get_active_row_number(); + if( currentRow>=0 && currentRow < procparams::RAWParams::numFlatFileBlurTypes) + pp->raw.ff_BlurType = procparams::RAWParams::ff_BlurTypestring[currentRow]; + + if (pedited) { + pedited->raw.ff_file = ffChanged; + pedited->raw.ff_AutoSelect = !flatFieldAutoSelect->get_inconsistent(); + pedited->raw.ff_BlurRadius = flatFieldBlurRadius->getEditedState (); + pedited->raw.ff_clipControl = flatFieldClipControl->getEditedState (); + pedited->raw.ff_AutoClipControl = !flatFieldClipControl->getAutoInconsistent(); + pedited->raw.ff_BlurType = flatFieldBlurType->get_active_row_number() != procparams::RAWParams::numFlatFileBlurTypes; + } + +} + +void FlatField::adjusterChanged (Adjuster* a, double newval) +{ + if (listener) { + + Glib::ustring value = a->getTextValue(); + + if (a==flatFieldBlurRadius) + listener->panelChanged (EvFlatFieldBlurRadius, value); + else if (a==flatFieldClipControl) + listener->panelChanged (EvFlatFieldClipControl, value); + } +} + +void FlatField::adjusterAutoToggled (Adjuster* a, bool newval) { + + if (multiImage) { + if (flatFieldClipControl->getAutoInconsistent()) { + flatFieldClipControl->setAutoInconsistent(false); + flatFieldClipControl->setAutoValue(false); + } + else if (lastFFAutoClipCtrl) + flatFieldClipControl->setAutoInconsistent(true); + + lastFFAutoClipCtrl = flatFieldClipControl->getAutoValue(); + + } + + if (listener) { + if(a==flatFieldClipControl) { + if (flatFieldClipControl->getAutoInconsistent()) + listener->panelChanged (EvFlatFieldAutoClipControl, M("GENERAL_UNCHANGED")); + else if (flatFieldClipControl->getAutoValue()) + listener->panelChanged (EvFlatFieldAutoClipControl, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvFlatFieldAutoClipControl, M("GENERAL_DISABLED")); + } + } +} + +void FlatField::setBatchMode(bool batchMode) +{ + ToolPanel::setBatchMode (batchMode); + flatFieldBlurRadius->showEditedCB (); + flatFieldClipControl->showEditedCB (); +} + +void FlatField::setAdjusterBehavior (bool clipctrladd) { + flatFieldClipControl->setAddMode(clipctrladd); +} + +void FlatField::trimValues (rtengine::procparams::ProcParams* pp) { + flatFieldClipControl->trimValue(pp->raw.ff_clipControl); +} + +void FlatField::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + flatFieldBlurRadius->setDefault( defParams->raw.ff_BlurRadius); + flatFieldClipControl->setDefault( defParams->raw.ff_clipControl); + + if (pedited) { + flatFieldBlurRadius->setDefaultEditedState( pedited->raw.ff_BlurRadius ? Edited : UnEdited); + flatFieldClipControl->setDefaultEditedState( pedited->raw.ff_clipControl ? Edited : UnEdited); + } else { + flatFieldBlurRadius->setDefaultEditedState( Irrelevant ); + flatFieldClipControl->setDefaultEditedState( Irrelevant ); + } +} + +void FlatField::flatFieldFileChanged() +{ + ffChanged=true; + if (listener) + listener->panelChanged (EvFlatFieldFile, Glib::path_get_basename(flatFieldFile->get_filename())); +} + +void FlatField::flatFieldFile_Reset() +{ + ffChanged=true; + +// caution: I had to make this hack, because set_current_folder() doesn't work correctly! +// Because szeva doesn't exist since he was committed to happy hunting ground in Issue 316 +// we can use him now for this hack + flatFieldFile->set_filename (options.lastFlatfieldDir + "/szeva"); +// end of the hack + + if (!options.lastFlatfieldDir.empty()) + flatFieldFile->set_current_folder(options.lastFlatfieldDir); + + ffInfo->set_text(""); + if (listener) + listener->panelChanged (EvFlatFieldFile, M("GENERAL_NONE") ); +} + +void FlatField::flatFieldBlurTypeChanged () +{ + int curSelection = flatFieldBlurType->get_active_row_number(); + + Glib::ustring s=""; + if( curSelection>=0 && curSelection < procparams::RAWParams::numFlatFileBlurTypes) + s = flatFieldBlurType->get_active_text(); + + if (multiImage || curSelection == procparams::RAWParams::area_ff) + flatFieldClipControl->show(); + else + flatFieldClipControl->hide(); + + if (listener) + listener->panelChanged (EvFlatFieldBlurType, s); +} + +void FlatField::flatFieldAutoSelectChanged() +{ + if (batchMode) { + if (flatFieldAutoSelect->get_inconsistent()) { + flatFieldAutoSelect->set_inconsistent (false); + flatFieldAutoSelectconn.block (true); + flatFieldAutoSelect->set_active (false); + flatFieldAutoSelectconn.block (false); + } + else if (lastFFAutoSelect) + flatFieldAutoSelect->set_inconsistent (true); + + lastFFAutoSelect = flatFieldAutoSelect->get_active (); + } + hbff->set_sensitive( !flatFieldAutoSelect->get_active() ); + + if( flatFieldAutoSelect->get_active() && ffp && !batchMode){ + // retrieve the auto-selected ff filename + rtengine::RawImage *img = ffp->getFF(); + if( img ){ + ffInfo->set_text( Glib::ustring::compose("%1: f/%2", Glib::path_get_basename(img->get_filename()), img->get_aperture()) ); // !!! need to add focallength in mm and format aperture to ##.# + }else{ + ffInfo->set_text(Glib::ustring(M("TP_PREPROCESS_NO_FOUND"))); + } + } + else{ffInfo->set_text("");} + + if (listener) + listener->panelChanged (EvFlatFieldAutoSelect, flatFieldAutoSelect->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); + +} + +void FlatField::setShortcutPath(Glib::ustring path) +{ + if (path == "") return; +#ifdef WIN32 + // Dirty workaround, waiting for a clean solution by using exceptions! + if (!safe_is_shortcut_dir(path)) +#endif + { + if (lastShortcutPath != "") { + try { + flatFieldFile->remove_shortcut_folder(lastShortcutPath); + } + catch (Glib::Error &err) {} + } + lastShortcutPath = path; + try { + flatFieldFile->add_shortcut_folder(path); + } + catch (Glib::Error &err) {} + } +} diff --git a/rtgui/flatfield.h b/rtgui/flatfield.h index 12f9dacba..a37e93d76 100644 --- a/rtgui/flatfield.h +++ b/rtgui/flatfield.h @@ -1,81 +1,81 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _FLATFIELD_H_ -#define _FLATFIELD_H_ - -#include -#include -#include "adjuster.h" -#include "toolpanel.h" -#include "../rtengine/rawimage.h" -#include "guiutils.h" - -class FFProvider { - public: - virtual ~FFProvider() {} - virtual rtengine::RawImage* getFF() = 0; - virtual Glib::ustring GetCurrentImageFilePath() = 0; - // add other info here -}; - -class FlatField : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { - -protected: - - MyFileChooserButton *flatFieldFile; - std::auto_ptr flatFieldFilePersister; - Gtk::Label *ffLabel; - Gtk::Label *ffInfo; - Gtk::Button *flatFieldFileReset; - Gtk::CheckButton* flatFieldAutoSelect; - Adjuster* flatFieldClipControl; - Adjuster* flatFieldBlurRadius; - MyComboBoxText* flatFieldBlurType; - Gtk::HBox *hbff; - bool ffChanged; - bool lastFFAutoSelect; - bool lastFFAutoClipCtrl; - FFProvider *ffp; - sigc::connection flatFieldFileconn, flatFieldAutoSelectconn, flatFieldBlurTypeconn; - Glib::ustring lastShortcutPath; - bool b_filter_asCurrent; - bool israw; - -public: - - FlatField (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void setAdjusterBehavior (bool clipctrladd); - void trimValues (rtengine::procparams::ProcParams* pp); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - - void adjusterChanged (Adjuster* a, double newval); - void adjusterAutoToggled (Adjuster* a, bool newval); - void flatFieldFileChanged (); - void flatFieldFile_Reset (); - void flatFieldAutoSelectChanged (); - void flatFieldBlurTypeChanged (); - void setShortcutPath(Glib::ustring path); - void setFFProvider (FFProvider* p) { ffp = p; }; -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _FLATFIELD_H_ +#define _FLATFIELD_H_ + +#include +#include +#include "adjuster.h" +#include "toolpanel.h" +#include "../rtengine/rawimage.h" +#include "guiutils.h" + +class FFProvider { + public: + virtual ~FFProvider() {} + virtual rtengine::RawImage* getFF() = 0; + virtual Glib::ustring GetCurrentImageFilePath() = 0; + // add other info here +}; + +class FlatField : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { + +protected: + + MyFileChooserButton *flatFieldFile; + std::auto_ptr flatFieldFilePersister; + Gtk::Label *ffLabel; + Gtk::Label *ffInfo; + Gtk::Button *flatFieldFileReset; + Gtk::CheckButton* flatFieldAutoSelect; + Adjuster* flatFieldClipControl; + Adjuster* flatFieldBlurRadius; + MyComboBoxText* flatFieldBlurType; + Gtk::HBox *hbff; + bool ffChanged; + bool lastFFAutoSelect; + bool lastFFAutoClipCtrl; + FFProvider *ffp; + sigc::connection flatFieldFileconn, flatFieldAutoSelectconn, flatFieldBlurTypeconn; + Glib::ustring lastShortcutPath; + bool b_filter_asCurrent; + bool israw; + +public: + + FlatField (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setAdjusterBehavior (bool clipctrladd); + void trimValues (rtengine::procparams::ProcParams* pp); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + + void adjusterChanged (Adjuster* a, double newval); + void adjusterAutoToggled (Adjuster* a, bool newval); + void flatFieldFileChanged (); + void flatFieldFile_Reset (); + void flatFieldAutoSelectChanged (); + void flatFieldBlurTypeChanged (); + void setShortcutPath(Glib::ustring path); + void setFFProvider (FFProvider* p) { ffp = p; }; +}; + +#endif diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index ca5d41cd5..aec3e19ee 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -145,13 +145,13 @@ void drawCrop (Cairo::RefPtr cr, int imx, int imy, int imw, int double c2y = (cparams.y+cparams.h-starty)*scale - (fullImageVisible ? 0.0 : 1.0); // crop overlay color, linked with crop windows background if (options.bgcolor==0 || !useBgColor) - cr->set_source_rgba (options.cutOverlayBrush[0], options.cutOverlayBrush[1], options.cutOverlayBrush[2], options.cutOverlayBrush[3]); + cr->set_source_rgba (options.cutOverlayBrush[0], options.cutOverlayBrush[1], options.cutOverlayBrush[2], options.cutOverlayBrush[3]); else if (options.bgcolor==1) cr->set_source_rgb (0,0,0); else if (options.bgcolor==2) cr->set_source_rgb (1,1,1); - - + + cr->rectangle (imx, imy, imw+0.5, round(c1y)+0.5); cr->rectangle (imx, round(imy+c2y)+0.5, imw+0.5, round(imh-c2y)+0.5); cr->rectangle (imx, round(imy+c1y)+0.5, round(c1x)+0.5, round(c2y-c1y+1)+0.5); diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 00ae1f5cb..bc2a83de6 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -1,262 +1,262 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "inspector.h" -#include "guiutils.h" -#include -#include "cursormanager.h" -#include "guiutils.h" -#include "options.h" -#include "../rtengine/safegtk.h" -#include "../rtengine/previewimage.h" - -extern Options options; - -InspectorBuffer::InspectorBuffer(const Glib::ustring &imagePath) : currTransform(0), fromRaw(false) { - if (!imagePath.empty() && safe_file_test(imagePath, Glib::FILE_TEST_EXISTS) && !safe_file_test(imagePath, Glib::FILE_TEST_IS_DIR)) { - imgPath = imagePath; - - // generate thumbnail image - Glib::ustring ext = getExtension (imagePath); - if (ext=="") { - imgPath.clear(); - return; - } - - rtengine::PreviewImage pi(imagePath, ext, rtengine::PreviewImage::PIM_EmbeddedOrRaw); - Cairo::RefPtr imageSurface = pi.getImage(); - - if (imageSurface) { - imgBuffer.setSurface(imageSurface); - fromRaw = true; - } - else { - imgPath.clear(); - } - } -} - -/* -InspectorBuffer::~InspectorBuffer() { -} -*/ - -int InspectorBuffer::infoFromImage (const Glib::ustring& fname) { - - rtengine::ImageMetaData* idata = rtengine::ImageMetaData::fromFile (fname, NULL); - if (!idata) - return 0; - - int deg = 0; - if (idata->hasExif()) { - if (idata->getOrientation()=="Rotate 90 CW" ) deg = 90; - else if (idata->getOrientation()=="Rotate 180" ) deg = 180; - else if (idata->getOrientation()=="Rotate 270 CW") deg = 270; - } - delete idata; - return deg; -} - -Inspector::Inspector () : currImage(NULL), zoom(0.0), active(false) {} - -Inspector::~Inspector() { - deleteBuffers(); -} - -bool Inspector::on_expose_event (GdkEventExpose* event) { - - Glib::RefPtr win = get_window(); - if (!win) - return false; - - if (!active) { - active = true; - } - - - // cleanup the region - - - if (currImage && currImage->imgBuffer.surfaceCreated()) { - // this will eventually create/update the off-screen pixmap - - // compute the displayed area - Coord availableSize; - Coord topLeft; - Coord displayedSize; - Coord dest(0, 0); - win->get_size(availableSize.x, availableSize.y); - int imW = currImage->imgBuffer.getWidth(); - int imH = currImage->imgBuffer.getHeight(); - - if (imW < availableSize.x) { - // center the image in the available space along X - topLeft.x = 0; - displayedSize.x = availableSize.x; - dest.x = (availableSize.x - imW) / 2; - } - else { - // partial image display - // double clamp - topLeft.x = center.x + availableSize.x/2; - topLeft.x = rtengine::min(topLeft.x, imW); - topLeft.x -= availableSize.x; - topLeft.x = rtengine::max(topLeft.x, 0); - } - - if (imH < availableSize.y) { - // center the image in the available space along Y - topLeft.y = 0; - displayedSize.y = availableSize.y; - dest.y = (availableSize.y - imH) / 2; - } - else { - // partial image display - // double clamp - topLeft.y = center.y + availableSize.y/2; - topLeft.y = rtengine::min(topLeft.y, imH); - topLeft.y -= availableSize.y; - topLeft.y = rtengine::max(topLeft.y, 0); - } - - //printf("center: %d, %d (img: %d, %d) (availableSize: %d, %d) (topLeft: %d, %d)\n", center.x, center.y, imW, imH, availableSize.x, availableSize.y, topLeft.x, topLeft.y); - - // define the destination area - currImage->imgBuffer.setDrawRectangle(win, dest.x, dest.y, rtengine::min(availableSize.x-dest.x, imW), rtengine::min(availableSize.y-dest.y,imH), false); - currImage->imgBuffer.setSrcOffset(topLeft.x, topLeft.y); - - if (!currImage->imgBuffer.surfaceCreated()) { - return false; - } - - // Draw! - - Gdk::Color c; - Cairo::RefPtr cr = win->create_cairo_context(); - Glib::RefPtr style = get_style(); - - // draw the background - c = style->get_bg (Gtk::STATE_NORMAL); - cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); - cr->set_line_width (0); - cr->rectangle (0, 0, availableSize.x, availableSize.y); - cr->fill (); - - currImage->imgBuffer.copySurface(win); - - // draw the frame - c = style->get_fg (Gtk::STATE_NORMAL); - cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); - cr->set_line_width (1); - cr->rectangle (0.5, 0.5, availableSize.x-1, availableSize.y-1); - cr->stroke (); - } - return true; -} - -void Inspector::mouseMove (rtengine::Coord2D pos, int transform) { - if (!active) - return; - - if (currImage) - center.set(int(rtengine::LIM01(pos.x)*double(currImage->imgBuffer.getWidth())), int(rtengine::LIM01(pos.y)*double(currImage->imgBuffer.getHeight()))); - else - center.set(0,0); - queue_draw(); -} - -void Inspector::switchImage (const Glib::ustring &fullPath) { - if (!active) - return; - - // we first check the size of the list, it may have been changed in Preference - if (images.size() > size_t(options.maxInspectorBuffers)) { - // deleting the last entries - for (size_t i=images.size()-1; i>size_t(options.maxInspectorBuffers-1); --i) { - delete images.at(i); - images.at(i) = NULL; - } - // resizing down - images.resize(options.maxInspectorBuffers); - } - - if (fullPath.empty()) { - currImage = NULL; - queue_draw(); - return; - } - else { - bool found = false; - for (size_t i=0; iimgPath==fullPath) { - currImage = images.at(i); - - // rolling the list 1 step to the beginning - for (size_t j=i; jimgPath.empty()) { - images.push_back(iBuffer); - currImage = images.at(images.size()-1); - } - else { - currImage = NULL; - } - } - } -} - -void Inspector::deleteBuffers () { - for (size_t i=0; i + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "inspector.h" +#include "guiutils.h" +#include +#include "cursormanager.h" +#include "guiutils.h" +#include "options.h" +#include "../rtengine/safegtk.h" +#include "../rtengine/previewimage.h" + +extern Options options; + +InspectorBuffer::InspectorBuffer(const Glib::ustring &imagePath) : currTransform(0), fromRaw(false) { + if (!imagePath.empty() && safe_file_test(imagePath, Glib::FILE_TEST_EXISTS) && !safe_file_test(imagePath, Glib::FILE_TEST_IS_DIR)) { + imgPath = imagePath; + + // generate thumbnail image + Glib::ustring ext = getExtension (imagePath); + if (ext=="") { + imgPath.clear(); + return; + } + + rtengine::PreviewImage pi(imagePath, ext, rtengine::PreviewImage::PIM_EmbeddedOrRaw); + Cairo::RefPtr imageSurface = pi.getImage(); + + if (imageSurface) { + imgBuffer.setSurface(imageSurface); + fromRaw = true; + } + else { + imgPath.clear(); + } + } +} + +/* +InspectorBuffer::~InspectorBuffer() { +} +*/ + +int InspectorBuffer::infoFromImage (const Glib::ustring& fname) { + + rtengine::ImageMetaData* idata = rtengine::ImageMetaData::fromFile (fname, NULL); + if (!idata) + return 0; + + int deg = 0; + if (idata->hasExif()) { + if (idata->getOrientation()=="Rotate 90 CW" ) deg = 90; + else if (idata->getOrientation()=="Rotate 180" ) deg = 180; + else if (idata->getOrientation()=="Rotate 270 CW") deg = 270; + } + delete idata; + return deg; +} + +Inspector::Inspector () : currImage(NULL), zoom(0.0), active(false) {} + +Inspector::~Inspector() { + deleteBuffers(); +} + +bool Inspector::on_expose_event (GdkEventExpose* event) { + + Glib::RefPtr win = get_window(); + if (!win) + return false; + + if (!active) { + active = true; + } + + + // cleanup the region + + + if (currImage && currImage->imgBuffer.surfaceCreated()) { + // this will eventually create/update the off-screen pixmap + + // compute the displayed area + Coord availableSize; + Coord topLeft; + Coord displayedSize; + Coord dest(0, 0); + win->get_size(availableSize.x, availableSize.y); + int imW = currImage->imgBuffer.getWidth(); + int imH = currImage->imgBuffer.getHeight(); + + if (imW < availableSize.x) { + // center the image in the available space along X + topLeft.x = 0; + displayedSize.x = availableSize.x; + dest.x = (availableSize.x - imW) / 2; + } + else { + // partial image display + // double clamp + topLeft.x = center.x + availableSize.x/2; + topLeft.x = rtengine::min(topLeft.x, imW); + topLeft.x -= availableSize.x; + topLeft.x = rtengine::max(topLeft.x, 0); + } + + if (imH < availableSize.y) { + // center the image in the available space along Y + topLeft.y = 0; + displayedSize.y = availableSize.y; + dest.y = (availableSize.y - imH) / 2; + } + else { + // partial image display + // double clamp + topLeft.y = center.y + availableSize.y/2; + topLeft.y = rtengine::min(topLeft.y, imH); + topLeft.y -= availableSize.y; + topLeft.y = rtengine::max(topLeft.y, 0); + } + + //printf("center: %d, %d (img: %d, %d) (availableSize: %d, %d) (topLeft: %d, %d)\n", center.x, center.y, imW, imH, availableSize.x, availableSize.y, topLeft.x, topLeft.y); + + // define the destination area + currImage->imgBuffer.setDrawRectangle(win, dest.x, dest.y, rtengine::min(availableSize.x-dest.x, imW), rtengine::min(availableSize.y-dest.y,imH), false); + currImage->imgBuffer.setSrcOffset(topLeft.x, topLeft.y); + + if (!currImage->imgBuffer.surfaceCreated()) { + return false; + } + + // Draw! + + Gdk::Color c; + Cairo::RefPtr cr = win->create_cairo_context(); + Glib::RefPtr style = get_style(); + + // draw the background + c = style->get_bg (Gtk::STATE_NORMAL); + cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); + cr->set_line_width (0); + cr->rectangle (0, 0, availableSize.x, availableSize.y); + cr->fill (); + + currImage->imgBuffer.copySurface(win); + + // draw the frame + c = style->get_fg (Gtk::STATE_NORMAL); + cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); + cr->set_line_width (1); + cr->rectangle (0.5, 0.5, availableSize.x-1, availableSize.y-1); + cr->stroke (); + } + return true; +} + +void Inspector::mouseMove (rtengine::Coord2D pos, int transform) { + if (!active) + return; + + if (currImage) + center.set(int(rtengine::LIM01(pos.x)*double(currImage->imgBuffer.getWidth())), int(rtengine::LIM01(pos.y)*double(currImage->imgBuffer.getHeight()))); + else + center.set(0,0); + queue_draw(); +} + +void Inspector::switchImage (const Glib::ustring &fullPath) { + if (!active) + return; + + // we first check the size of the list, it may have been changed in Preference + if (images.size() > size_t(options.maxInspectorBuffers)) { + // deleting the last entries + for (size_t i=images.size()-1; i>size_t(options.maxInspectorBuffers-1); --i) { + delete images.at(i); + images.at(i) = NULL; + } + // resizing down + images.resize(options.maxInspectorBuffers); + } + + if (fullPath.empty()) { + currImage = NULL; + queue_draw(); + return; + } + else { + bool found = false; + for (size_t i=0; iimgPath==fullPath) { + currImage = images.at(i); + + // rolling the list 1 step to the beginning + for (size_t j=i; jimgPath.empty()) { + images.push_back(iBuffer); + currImage = images.at(images.size()-1); + } + else { + currImage = NULL; + } + } + } +} + +void Inspector::deleteBuffers () { + for (size_t i=0; i - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "labcurve.h" -#include -#include "../rtengine/improcfun.h" -#include "edit.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -LCurve::LCurve () : FoldableToolPanel(this, "labcurves", M("TP_LABCURVE_LABEL")) { - - std::vector milestones; - - brightness = Gtk::manage (new Adjuster (M("TP_LABCURVE_BRIGHTNESS"), -100., 100., 1., 0.)); - contrast = Gtk::manage (new Adjuster (M("TP_LABCURVE_CONTRAST"), -100., 100., 1., 0.)); - chromaticity = Gtk::manage (new Adjuster (M("TP_LABCURVE_CHROMATICITY"), -100., 100., 1., 0.)); - chromaticity->set_tooltip_markup(M("TP_LABCURVE_CHROMA_TOOLTIP")); - - pack_start (*brightness); - brightness->show (); - - pack_start (*contrast); - contrast->show (); - - pack_start (*chromaticity); - chromaticity->show (); - - brightness->setAdjusterListener (this); - contrast->setAdjusterListener (this); - chromaticity->setAdjusterListener (this); - - //%%%%%%%%%%%%%%%%%% - Gtk::HSeparator *hsep2 = Gtk::manage (new Gtk::HSeparator()); - hsep2->show (); - pack_start (*hsep2, Gtk::PACK_EXPAND_WIDGET, 4); - - avoidcolorshift = Gtk::manage (new Gtk::CheckButton (M("TP_LABCURVE_AVOIDCOLORSHIFT"))); - avoidcolorshift->set_tooltip_text (M("TP_LABCURVE_AVOIDCOLORSHIFT_TOOLTIP")); - pack_start (*avoidcolorshift, Gtk::PACK_SHRINK, 4); - - lcredsk = Gtk::manage (new Gtk::CheckButton (M("TP_LABCURVE_LCREDSK"))); - lcredsk->set_tooltip_markup (M("TP_LABCURVE_LCREDSK_TIP")); - pack_start (*lcredsk); - - rstprotection = Gtk::manage ( new Adjuster (M("TP_LABCURVE_RSTPROTECTION"), 0., 100., 0.1, 0.) ); - pack_start (*rstprotection); - rstprotection->show (); - - rstprotection->setAdjusterListener (this); - rstprotection->set_tooltip_text (M("TP_LABCURVE_RSTPRO_TOOLTIP")); - - acconn = avoidcolorshift->signal_toggled().connect( sigc::mem_fun(*this, &LCurve::avoidcolorshift_toggled) ); - lcconn = lcredsk->signal_toggled().connect( sigc::mem_fun(*this, &LCurve::lcredsk_toggled) ); - - //%%%%%%%%%%%%%%%%%%% - - Gtk::HSeparator *hsep3 = Gtk::manage (new Gtk::HSeparator()); - hsep3->show (); - pack_start (*hsep3, Gtk::PACK_EXPAND_WIDGET, 4); - - curveEditorG = new CurveEditorGroup (options.lastLabCurvesDir); - curveEditorG->setCurveListener (this); - - lshape = static_cast(curveEditorG->addCurve(CT_Diagonal, "L*")); - lshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_LL_TOOLTIP")); - lshape->setEditID(EUID_Lab_LCurve, BT_SINGLEPLANE_FLOAT); - - ashape = static_cast(curveEditorG->addCurve(CT_Diagonal, "a*")); - ashape->setEditID(EUID_Lab_aCurve, BT_SINGLEPLANE_FLOAT); - - ashape->setRangeLabels( - M("TP_LABCURVE_CURVEEDITOR_A_RANGE1"), M("TP_LABCURVE_CURVEEDITOR_A_RANGE2"), - M("TP_LABCURVE_CURVEEDITOR_A_RANGE3"), M("TP_LABCURVE_CURVEEDITOR_A_RANGE4") - ); - //from green to magenta - milestones.clear(); - milestones.push_back( GradientMilestone(0., 0., 1., 0.) ); - milestones.push_back( GradientMilestone(1., 1., 0., 1.) ); - ashape->setBottomBarBgGradient(milestones); - ashape->setLeftBarBgGradient(milestones); - milestones.clear(); - - bshape = static_cast(curveEditorG->addCurve(CT_Diagonal, "b*")); - bshape->setRangeLabels( - M("TP_LABCURVE_CURVEEDITOR_B_RANGE1"), M("TP_LABCURVE_CURVEEDITOR_B_RANGE2"), - M("TP_LABCURVE_CURVEEDITOR_B_RANGE3"), M("TP_LABCURVE_CURVEEDITOR_B_RANGE4") - ); - bshape->setEditID(EUID_Lab_bCurve, BT_SINGLEPLANE_FLOAT); - - //from blue to yellow - milestones.clear(); - milestones.push_back( GradientMilestone(0., 0., 0., 1.) ); - milestones.push_back( GradientMilestone(1., 1., 1., 0.) ); - bshape->setBottomBarBgGradient(milestones); - bshape->setLeftBarBgGradient(milestones); - milestones.clear(); - - curveEditorG->newLine(); // ------------------------------------------------ second line - - lhshape = static_cast(curveEditorG->addCurve(CT_Flat, M("TP_LABCURVE_CURVEEDITOR_LH"))); - lhshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_LH_TOOLTIP")); - lhshape->setCurveColorProvider(this, 4); - lhshape->setEditID(EUID_Lab_LHCurve, BT_SINGLEPLANE_FLOAT); - - - chshape = static_cast(curveEditorG->addCurve(CT_Flat, M("TP_LABCURVE_CURVEEDITOR_CH"))); - chshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_CH_TOOLTIP")); - chshape->setCurveColorProvider(this, 1); - chshape->setEditID(EUID_Lab_CHCurve, BT_SINGLEPLANE_FLOAT); - - - hhshape = static_cast(curveEditorG->addCurve(CT_Flat, M("TP_LABCURVE_CURVEEDITOR_HH"))); - hhshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_HH_TOOLTIP")); - hhshape->setCurveColorProvider(this, 5); - hhshape->setEditID(EUID_Lab_HHCurve, BT_SINGLEPLANE_FLOAT); - - curveEditorG->newLine(); // ------------------------------------------------ 3rd line - - ccshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_LABCURVE_CURVEEDITOR_CC"))); - ccshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_CC_TOOLTIP")); - ccshape->setEditID(EUID_Lab_CCurve, BT_SINGLEPLANE_FLOAT); - ccshape->setRangeLabels( - M("TP_LABCURVE_CURVEEDITOR_CC_RANGE1"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE2"), - M("TP_LABCURVE_CURVEEDITOR_CC_RANGE3"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE4") - ); - - ccshape->setBottomBarColorProvider(this, 2); - ccshape->setLeftBarColorProvider(this, 2); - ccshape->setRangeDefaultMilestones(0.05, 0.2, 0.58); - - lcshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_LABCURVE_CURVEEDITOR_LC"))); - lcshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_LC_TOOLTIP")); - lcshape->setEditID(EUID_Lab_LCCurve, BT_SINGLEPLANE_FLOAT); - - // left and bottom bar uses the same caller id because the will display the same content - lcshape->setBottomBarColorProvider(this, 2); - lcshape->setRangeLabels( - M("TP_LABCURVE_CURVEEDITOR_CC_RANGE1"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE2"), - M("TP_LABCURVE_CURVEEDITOR_CC_RANGE3"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE4") - ); - lcshape->setRangeDefaultMilestones(0.05, 0.2, 0.58); - - clshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_LABCURVE_CURVEEDITOR_CL"))); - clshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_CL_TOOLTIP")); - clshape->setEditID(EUID_Lab_CLCurve, BT_SINGLEPLANE_FLOAT); - - clshape->setLeftBarColorProvider(this, 2); - clshape->setRangeDefaultMilestones(0.25, 0.5, 0.75); - milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); - milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); - - clshape->setBottomBarBgGradient(milestones); - - - // Setting the gradient milestones - - // from black to white - milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); - milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); - lshape->setBottomBarBgGradient(milestones); - lshape->setLeftBarBgGradient(milestones); - milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); - milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); - lcshape->setRangeDefaultMilestones(0.05, 0.2, 0.58); - - lcshape->setBottomBarBgGradient(milestones); - - milestones.at(0).r = milestones.at(0).g = milestones.at(0).b = 0.1; - milestones.at(1).r = milestones.at(1).g = milestones.at(1).b = 0.8; - lcshape->setLeftBarBgGradient(milestones); - - // whole hue range - milestones.clear(); - for (int i=0; i<7; i++) { - float R, G, B; - float x = float(i)*(1.0f/6.0); - Color::hsv2rgb01(x, 0.5f, 0.5f, R, G, B); - milestones.push_back( GradientMilestone(double(x), double(R), double(G), double(B)) ); - } - chshape->setBottomBarBgGradient(milestones); - lhshape->setBottomBarBgGradient(milestones); - hhshape->setBottomBarBgGradient(milestones); - - - // This will add the reset button at the end of the curveType buttons - curveEditorG->curveListComplete(); - - pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4); - -} - -LCurve::~LCurve () { - delete curveEditorG; -} - -void LCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { - - disableListener (); - - if (pedited) { - brightness->setEditedState (pedited->labCurve.brightness ? Edited : UnEdited); - contrast->setEditedState (pedited->labCurve.contrast ? Edited : UnEdited); - chromaticity->setEditedState (pedited->labCurve.chromaticity ? Edited : UnEdited); - - //%%%%%%%%%%%%%%%%%%%%%% - rstprotection->setEditedState (pedited->labCurve.rstprotection ? Edited : UnEdited); - avoidcolorshift->set_inconsistent (!pedited->labCurve.avoidcolorshift); - lcredsk->set_inconsistent (!pedited->labCurve.lcredsk); - - //%%%%%%%%%%%%%%%%%%%%%% - - lshape->setUnChanged (!pedited->labCurve.lcurve); - ashape->setUnChanged (!pedited->labCurve.acurve); - bshape->setUnChanged (!pedited->labCurve.bcurve); - ccshape->setUnChanged (!pedited->labCurve.cccurve); - chshape->setUnChanged (!pedited->labCurve.chcurve); - lhshape->setUnChanged (!pedited->labCurve.lhcurve); - hhshape->setUnChanged (!pedited->labCurve.hhcurve); - lcshape->setUnChanged (!pedited->labCurve.lccurve); - clshape->setUnChanged (!pedited->labCurve.clcurve); - } - - brightness->setValue (pp->labCurve.brightness); - contrast->setValue (pp->labCurve.contrast); - chromaticity->setValue (pp->labCurve.chromaticity); - adjusterChanged(chromaticity, pp->labCurve.chromaticity); // To update the GUI sensitiveness - - //%%%%%%%%%%%%%%%%%%%%%% - rstprotection->setValue (pp->labCurve.rstprotection); - - bwtconn.block (true); - acconn.block (true); - lcconn.block (true); - avoidcolorshift->set_active (pp->labCurve.avoidcolorshift); - lcredsk->set_active (pp->labCurve.lcredsk); - - bwtconn.block (false); - acconn.block (false); - lcconn.block (false); - - lastACVal = pp->labCurve.avoidcolorshift; - lastLCVal = pp->labCurve.lcredsk; - //%%%%%%%%%%%%%%%%%%%%%% - - lshape->setCurve (pp->labCurve.lcurve); - ashape->setCurve (pp->labCurve.acurve); - bshape->setCurve (pp->labCurve.bcurve); - ccshape->setCurve (pp->labCurve.cccurve); - chshape->setCurve (pp->labCurve.chcurve); - lhshape->setCurve (pp->labCurve.lhcurve); - hhshape->setCurve (pp->labCurve.hhcurve); - lcshape->setCurve (pp->labCurve.lccurve); - clshape->setCurve (pp->labCurve.clcurve); - - queue_draw(); - - enableListener (); -} - -void LCurve::autoOpenCurve () { - // Open up the first curve if selected - bool active = lshape->openIfNonlinear(); - if (!active) ashape->openIfNonlinear(); - if (!active) bshape->openIfNonlinear(); - if (!active) ccshape->openIfNonlinear(); - if (!active) chshape->openIfNonlinear(); - if (!active) lhshape->openIfNonlinear(); - if (!active) hhshape->openIfNonlinear(); - if (!active) lcshape->openIfNonlinear(); - if (!active) clshape->openIfNonlinear(); -} - -void LCurve::setEditProvider (EditDataProvider *provider) { - lshape->setEditProvider(provider); - ccshape->setEditProvider(provider); - lcshape->setEditProvider(provider); - clshape->setEditProvider(provider); - lhshape->setEditProvider(provider); - chshape->setEditProvider(provider); - hhshape->setEditProvider(provider); - ashape->setEditProvider(provider); - bshape->setEditProvider(provider); - -} - - -void LCurve::write (ProcParams* pp, ParamsEdited* pedited) { - - pp->labCurve.brightness = brightness->getValue (); - pp->labCurve.contrast = (int)contrast->getValue (); - pp->labCurve.chromaticity = (int)chromaticity->getValue (); - - //%%%%%%%%%%%%%%%%%%%%%% - pp->labCurve.avoidcolorshift = avoidcolorshift->get_active (); - pp->labCurve.lcredsk = lcredsk->get_active (); - - pp->labCurve.rstprotection = rstprotection->getValue (); - //%%%%%%%%%%%%%%%%%%%%%% - - pp->labCurve.lcurve = lshape->getCurve (); - pp->labCurve.acurve = ashape->getCurve (); - pp->labCurve.bcurve = bshape->getCurve (); - pp->labCurve.cccurve = ccshape->getCurve (); - pp->labCurve.chcurve = chshape->getCurve (); - pp->labCurve.lhcurve = lhshape->getCurve (); - pp->labCurve.hhcurve = hhshape->getCurve (); - pp->labCurve.lccurve = lcshape->getCurve (); - pp->labCurve.clcurve = clshape->getCurve (); - - if (pedited) { - pedited->labCurve.brightness = brightness->getEditedState (); - pedited->labCurve.contrast = contrast->getEditedState (); - pedited->labCurve.chromaticity = chromaticity->getEditedState (); - - //%%%%%%%%%%%%%%%%%%%%%% - pedited->labCurve.avoidcolorshift = !avoidcolorshift->get_inconsistent(); - pedited->labCurve.lcredsk = !lcredsk->get_inconsistent(); - - pedited->labCurve.rstprotection = rstprotection->getEditedState (); - //%%%%%%%%%%%%%%%%%%%%%% - - pedited->labCurve.lcurve = !lshape->isUnChanged (); - pedited->labCurve.acurve = !ashape->isUnChanged (); - pedited->labCurve.bcurve = !bshape->isUnChanged (); - pedited->labCurve.cccurve = !ccshape->isUnChanged (); - pedited->labCurve.chcurve = !chshape->isUnChanged (); - pedited->labCurve.lhcurve = !lhshape->isUnChanged (); - pedited->labCurve.hhcurve = !hhshape->isUnChanged (); - pedited->labCurve.lccurve = !lcshape->isUnChanged (); - pedited->labCurve.clcurve = !clshape->isUnChanged (); - } -} - -void LCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - - brightness->setDefault (defParams->labCurve.brightness); - contrast->setDefault (defParams->labCurve.contrast); - chromaticity->setDefault (defParams->labCurve.chromaticity); - rstprotection->setDefault (defParams->labCurve.rstprotection); - - if (pedited) { - brightness->setDefaultEditedState (pedited->labCurve.brightness ? Edited : UnEdited); - contrast->setDefaultEditedState (pedited->labCurve.contrast ? Edited : UnEdited); - chromaticity->setDefaultEditedState (pedited->labCurve.chromaticity ? Edited : UnEdited); - rstprotection->setDefaultEditedState (pedited->labCurve.rstprotection ? Edited : UnEdited); - - } - else { - brightness->setDefaultEditedState (Irrelevant); - contrast->setDefaultEditedState (Irrelevant); - chromaticity->setDefaultEditedState (Irrelevant); - rstprotection->setDefaultEditedState (Irrelevant); - } -} - -//%%%%%%%%%%%%%%%%%%%%%% -//Color shift control changed -void LCurve::avoidcolorshift_toggled () { - - if (batchMode) { - if (avoidcolorshift->get_inconsistent()) { - avoidcolorshift->set_inconsistent (false); - acconn.block (true); - avoidcolorshift->set_active (false); - acconn.block (false); - } - else if (lastACVal) - avoidcolorshift->set_inconsistent (true); - - lastACVal = avoidcolorshift->get_active (); - } - - if (listener) { - if (avoidcolorshift->get_active ()) - listener->panelChanged (EvLAvoidColorShift, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvLAvoidColorShift, M("GENERAL_DISABLED")); - } -} - -void LCurve::lcredsk_toggled () { - - if (batchMode) { - if (lcredsk->get_inconsistent()) { - lcredsk->set_inconsistent (false); - lcconn.block (true); - lcredsk->set_active (false); - lcconn.block (false); - } - else if (lastLCVal) - lcredsk->set_inconsistent (true); - - lastLCVal = lcredsk->get_active (); - } - else { - lcshape->refresh(); - } - - if (listener) { - if (lcredsk->get_active ()) - listener->panelChanged (EvLLCredsk, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvLLCredsk, M("GENERAL_DISABLED")); - } -} - -//%%%%%%%%%%%%%%%%%%%%%% - -/* - * Curve listener - * - * If more than one curve has been added, the curve listener is automatically - * set to 'multi=true', and send a pointer of the modified curve in a parameter - */ -void LCurve::curveChanged (CurveEditor* ce) { - - if (listener) { - if (ce == lshape) - listener->panelChanged (EvLLCurve, M("HISTORY_CUSTOMCURVE")); - if (ce == ashape) - listener->panelChanged (EvLaCurve, M("HISTORY_CUSTOMCURVE")); - if (ce == bshape) - listener->panelChanged (EvLbCurve, M("HISTORY_CUSTOMCURVE")); - if (ce == ccshape) - listener->panelChanged (EvLCCCurve, M("HISTORY_CUSTOMCURVE")); - if (ce == chshape) - listener->panelChanged (EvLCHCurve, M("HISTORY_CUSTOMCURVE")); - if (ce == lhshape) - listener->panelChanged (EvLLHCurve, M("HISTORY_CUSTOMCURVE")); - if (ce == hhshape) - listener->panelChanged (EvLHHCurve, M("HISTORY_CUSTOMCURVE")); - if (ce == lcshape) - listener->panelChanged (EvLLCCurve, M("HISTORY_CUSTOMCURVE")); - if (ce == clshape) - listener->panelChanged (EvLCLCurve, M("HISTORY_CUSTOMCURVE")); - } -} - -void LCurve::adjusterChanged (Adjuster* a, double newval) { - - Glib::ustring costr; - if (a==brightness) - costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), a->getValue()); - else if (a==rstprotection) - costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(1), a->getValue()); - else - costr = Glib::ustring::format ((int)a->getValue()); - - if (a==brightness) { - if (listener) listener->panelChanged (EvLBrightness, costr); - } - else if (a==contrast) { - if (listener) listener->panelChanged (EvLContrast, costr); - } - else if (a==rstprotection) { - if (listener) listener->panelChanged (EvLRSTProtection, costr); - } - else if (a==chromaticity) { - if (multiImage) { - //if chromaticity==-100 (lowest value), we enter the B&W mode and avoid color shift and rstprotection has no effect - rstprotection->set_sensitive( true ); - avoidcolorshift->set_sensitive( true ); - lcredsk->set_sensitive( true ); - } - else { - //if chromaticity==-100 (lowest value), we enter the B&W mode and avoid color shift and rstprotection has no effect - rstprotection->set_sensitive( int(newval)> -100 );//no reason for grey rstprotection - avoidcolorshift->set_sensitive( int(newval)> -100 ); - lcredsk->set_sensitive( int(newval)> -100 ); - } - if (listener) listener->panelChanged (EvLSaturation, costr); - } -} - -void LCurve::colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller) { - - float R, G, B; - - if (elemType==ColorCaller::CCET_VERTICAL_BAR) - valY = 0.5; - - if (callerId == 1) { // ch - main curve - - Color::hsv2rgb01(float(valX), float(valY), 0.5f, R, G, B); - } - else if (callerId == 2) { // cc - bottom bar - - float value = (1.f - 0.7f) * float(valX) + 0.7f; - // whole hue range - // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) - Color::hsv2rgb01(float(valY), float(valX), value, R, G, B); - } - else if (callerId == 3) { // lc - bottom bar - - float value = (1.f - 0.7f) * float(valX) + 0.7f; - if (lcredsk->get_active()) { - // skin range - // -0.1 rad < Hue < 1.6 rad - // Y axis / from 0.92 up to 0.14056 - float hue = (1.14056f - 0.92f) * float(valY) + 0.92f; - if (hue > 1.0f) hue -= 1.0f; - // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) - Color::hsv2rgb01(hue, float(valX), value, R, G, B); - } - else { - // whole hue range - // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) - Color::hsv2rgb01(float(valY), float(valX), value, R, G, B); - } - } - else if (callerId == 4) { // LH - bottom bar - Color::hsv2rgb01(float(valX), 0.5f, float(valY), R, G, B); - } - else if (callerId == 5) { // HH - bottom bar - float h = float((valY - 0.5) * 0.3 + valX); - if (h > 1.0f) - h -= 1.0f; - else if (h < 0.0f) - h += 1.0f; - Color::hsv2rgb01(h, 0.5f, 0.5f, R, G, B); - } - caller->ccRed = double(R); - caller->ccGreen = double(G); - caller->ccBlue = double(B); -} - -void LCurve::setBatchMode (bool batchMode) { - - ToolPanel::setBatchMode (batchMode); - brightness->showEditedCB (); - contrast->showEditedCB (); - chromaticity->showEditedCB (); - rstprotection->showEditedCB (); - - curveEditorG->setBatchMode (batchMode); - lcshape->setBottomBarColorProvider(NULL, -1); - lcshape->setLeftBarColorProvider(NULL, -1); -} - - -void LCurve::updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve,/* LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma){ - - lshape->updateBackgroundHistogram (histLCurve); - ccshape->updateBackgroundHistogram (histCCurve); -// clshape->updateBackgroundHistogram (histCLurve); -// lcshape->updateBackgroundHistogram (histLLCurve); - -} - -void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd) { - - brightness->setAddMode(bradd); - contrast->setAddMode(contradd); - chromaticity->setAddMode(satadd); -} - -void LCurve::trimValues (rtengine::procparams::ProcParams* pp) { - - brightness->trimValue(pp->labCurve.brightness); - contrast->trimValue(pp->labCurve.contrast); - chromaticity->trimValue(pp->labCurve.chromaticity); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "labcurve.h" +#include +#include "../rtengine/improcfun.h" +#include "edit.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +LCurve::LCurve () : FoldableToolPanel(this, "labcurves", M("TP_LABCURVE_LABEL")) { + + std::vector milestones; + + brightness = Gtk::manage (new Adjuster (M("TP_LABCURVE_BRIGHTNESS"), -100., 100., 1., 0.)); + contrast = Gtk::manage (new Adjuster (M("TP_LABCURVE_CONTRAST"), -100., 100., 1., 0.)); + chromaticity = Gtk::manage (new Adjuster (M("TP_LABCURVE_CHROMATICITY"), -100., 100., 1., 0.)); + chromaticity->set_tooltip_markup(M("TP_LABCURVE_CHROMA_TOOLTIP")); + + pack_start (*brightness); + brightness->show (); + + pack_start (*contrast); + contrast->show (); + + pack_start (*chromaticity); + chromaticity->show (); + + brightness->setAdjusterListener (this); + contrast->setAdjusterListener (this); + chromaticity->setAdjusterListener (this); + + //%%%%%%%%%%%%%%%%%% + Gtk::HSeparator *hsep2 = Gtk::manage (new Gtk::HSeparator()); + hsep2->show (); + pack_start (*hsep2, Gtk::PACK_EXPAND_WIDGET, 4); + + avoidcolorshift = Gtk::manage (new Gtk::CheckButton (M("TP_LABCURVE_AVOIDCOLORSHIFT"))); + avoidcolorshift->set_tooltip_text (M("TP_LABCURVE_AVOIDCOLORSHIFT_TOOLTIP")); + pack_start (*avoidcolorshift, Gtk::PACK_SHRINK, 4); + + lcredsk = Gtk::manage (new Gtk::CheckButton (M("TP_LABCURVE_LCREDSK"))); + lcredsk->set_tooltip_markup (M("TP_LABCURVE_LCREDSK_TIP")); + pack_start (*lcredsk); + + rstprotection = Gtk::manage ( new Adjuster (M("TP_LABCURVE_RSTPROTECTION"), 0., 100., 0.1, 0.) ); + pack_start (*rstprotection); + rstprotection->show (); + + rstprotection->setAdjusterListener (this); + rstprotection->set_tooltip_text (M("TP_LABCURVE_RSTPRO_TOOLTIP")); + + acconn = avoidcolorshift->signal_toggled().connect( sigc::mem_fun(*this, &LCurve::avoidcolorshift_toggled) ); + lcconn = lcredsk->signal_toggled().connect( sigc::mem_fun(*this, &LCurve::lcredsk_toggled) ); + + //%%%%%%%%%%%%%%%%%%% + + Gtk::HSeparator *hsep3 = Gtk::manage (new Gtk::HSeparator()); + hsep3->show (); + pack_start (*hsep3, Gtk::PACK_EXPAND_WIDGET, 4); + + curveEditorG = new CurveEditorGroup (options.lastLabCurvesDir); + curveEditorG->setCurveListener (this); + + lshape = static_cast(curveEditorG->addCurve(CT_Diagonal, "L*")); + lshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_LL_TOOLTIP")); + lshape->setEditID(EUID_Lab_LCurve, BT_SINGLEPLANE_FLOAT); + + ashape = static_cast(curveEditorG->addCurve(CT_Diagonal, "a*")); + ashape->setEditID(EUID_Lab_aCurve, BT_SINGLEPLANE_FLOAT); + + ashape->setRangeLabels( + M("TP_LABCURVE_CURVEEDITOR_A_RANGE1"), M("TP_LABCURVE_CURVEEDITOR_A_RANGE2"), + M("TP_LABCURVE_CURVEEDITOR_A_RANGE3"), M("TP_LABCURVE_CURVEEDITOR_A_RANGE4") + ); + //from green to magenta + milestones.clear(); + milestones.push_back( GradientMilestone(0., 0., 1., 0.) ); + milestones.push_back( GradientMilestone(1., 1., 0., 1.) ); + ashape->setBottomBarBgGradient(milestones); + ashape->setLeftBarBgGradient(milestones); + milestones.clear(); + + bshape = static_cast(curveEditorG->addCurve(CT_Diagonal, "b*")); + bshape->setRangeLabels( + M("TP_LABCURVE_CURVEEDITOR_B_RANGE1"), M("TP_LABCURVE_CURVEEDITOR_B_RANGE2"), + M("TP_LABCURVE_CURVEEDITOR_B_RANGE3"), M("TP_LABCURVE_CURVEEDITOR_B_RANGE4") + ); + bshape->setEditID(EUID_Lab_bCurve, BT_SINGLEPLANE_FLOAT); + + //from blue to yellow + milestones.clear(); + milestones.push_back( GradientMilestone(0., 0., 0., 1.) ); + milestones.push_back( GradientMilestone(1., 1., 1., 0.) ); + bshape->setBottomBarBgGradient(milestones); + bshape->setLeftBarBgGradient(milestones); + milestones.clear(); + + curveEditorG->newLine(); // ------------------------------------------------ second line + + lhshape = static_cast(curveEditorG->addCurve(CT_Flat, M("TP_LABCURVE_CURVEEDITOR_LH"))); + lhshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_LH_TOOLTIP")); + lhshape->setCurveColorProvider(this, 4); + lhshape->setEditID(EUID_Lab_LHCurve, BT_SINGLEPLANE_FLOAT); + + + chshape = static_cast(curveEditorG->addCurve(CT_Flat, M("TP_LABCURVE_CURVEEDITOR_CH"))); + chshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_CH_TOOLTIP")); + chshape->setCurveColorProvider(this, 1); + chshape->setEditID(EUID_Lab_CHCurve, BT_SINGLEPLANE_FLOAT); + + + hhshape = static_cast(curveEditorG->addCurve(CT_Flat, M("TP_LABCURVE_CURVEEDITOR_HH"))); + hhshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_HH_TOOLTIP")); + hhshape->setCurveColorProvider(this, 5); + hhshape->setEditID(EUID_Lab_HHCurve, BT_SINGLEPLANE_FLOAT); + + curveEditorG->newLine(); // ------------------------------------------------ 3rd line + + ccshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_LABCURVE_CURVEEDITOR_CC"))); + ccshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_CC_TOOLTIP")); + ccshape->setEditID(EUID_Lab_CCurve, BT_SINGLEPLANE_FLOAT); + ccshape->setRangeLabels( + M("TP_LABCURVE_CURVEEDITOR_CC_RANGE1"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE2"), + M("TP_LABCURVE_CURVEEDITOR_CC_RANGE3"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE4") + ); + + ccshape->setBottomBarColorProvider(this, 2); + ccshape->setLeftBarColorProvider(this, 2); + ccshape->setRangeDefaultMilestones(0.05, 0.2, 0.58); + + lcshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_LABCURVE_CURVEEDITOR_LC"))); + lcshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_LC_TOOLTIP")); + lcshape->setEditID(EUID_Lab_LCCurve, BT_SINGLEPLANE_FLOAT); + + // left and bottom bar uses the same caller id because the will display the same content + lcshape->setBottomBarColorProvider(this, 2); + lcshape->setRangeLabels( + M("TP_LABCURVE_CURVEEDITOR_CC_RANGE1"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE2"), + M("TP_LABCURVE_CURVEEDITOR_CC_RANGE3"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE4") + ); + lcshape->setRangeDefaultMilestones(0.05, 0.2, 0.58); + + clshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_LABCURVE_CURVEEDITOR_CL"))); + clshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_CL_TOOLTIP")); + clshape->setEditID(EUID_Lab_CLCurve, BT_SINGLEPLANE_FLOAT); + + clshape->setLeftBarColorProvider(this, 2); + clshape->setRangeDefaultMilestones(0.25, 0.5, 0.75); + milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); + milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); + + clshape->setBottomBarBgGradient(milestones); + + + // Setting the gradient milestones + + // from black to white + milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); + milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); + lshape->setBottomBarBgGradient(milestones); + lshape->setLeftBarBgGradient(milestones); + milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); + milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); + lcshape->setRangeDefaultMilestones(0.05, 0.2, 0.58); + + lcshape->setBottomBarBgGradient(milestones); + + milestones.at(0).r = milestones.at(0).g = milestones.at(0).b = 0.1; + milestones.at(1).r = milestones.at(1).g = milestones.at(1).b = 0.8; + lcshape->setLeftBarBgGradient(milestones); + + // whole hue range + milestones.clear(); + for (int i=0; i<7; i++) { + float R, G, B; + float x = float(i)*(1.0f/6.0); + Color::hsv2rgb01(x, 0.5f, 0.5f, R, G, B); + milestones.push_back( GradientMilestone(double(x), double(R), double(G), double(B)) ); + } + chshape->setBottomBarBgGradient(milestones); + lhshape->setBottomBarBgGradient(milestones); + hhshape->setBottomBarBgGradient(milestones); + + + // This will add the reset button at the end of the curveType buttons + curveEditorG->curveListComplete(); + + pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4); + +} + +LCurve::~LCurve () { + delete curveEditorG; +} + +void LCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + brightness->setEditedState (pedited->labCurve.brightness ? Edited : UnEdited); + contrast->setEditedState (pedited->labCurve.contrast ? Edited : UnEdited); + chromaticity->setEditedState (pedited->labCurve.chromaticity ? Edited : UnEdited); + + //%%%%%%%%%%%%%%%%%%%%%% + rstprotection->setEditedState (pedited->labCurve.rstprotection ? Edited : UnEdited); + avoidcolorshift->set_inconsistent (!pedited->labCurve.avoidcolorshift); + lcredsk->set_inconsistent (!pedited->labCurve.lcredsk); + + //%%%%%%%%%%%%%%%%%%%%%% + + lshape->setUnChanged (!pedited->labCurve.lcurve); + ashape->setUnChanged (!pedited->labCurve.acurve); + bshape->setUnChanged (!pedited->labCurve.bcurve); + ccshape->setUnChanged (!pedited->labCurve.cccurve); + chshape->setUnChanged (!pedited->labCurve.chcurve); + lhshape->setUnChanged (!pedited->labCurve.lhcurve); + hhshape->setUnChanged (!pedited->labCurve.hhcurve); + lcshape->setUnChanged (!pedited->labCurve.lccurve); + clshape->setUnChanged (!pedited->labCurve.clcurve); + } + + brightness->setValue (pp->labCurve.brightness); + contrast->setValue (pp->labCurve.contrast); + chromaticity->setValue (pp->labCurve.chromaticity); + adjusterChanged(chromaticity, pp->labCurve.chromaticity); // To update the GUI sensitiveness + + //%%%%%%%%%%%%%%%%%%%%%% + rstprotection->setValue (pp->labCurve.rstprotection); + + bwtconn.block (true); + acconn.block (true); + lcconn.block (true); + avoidcolorshift->set_active (pp->labCurve.avoidcolorshift); + lcredsk->set_active (pp->labCurve.lcredsk); + + bwtconn.block (false); + acconn.block (false); + lcconn.block (false); + + lastACVal = pp->labCurve.avoidcolorshift; + lastLCVal = pp->labCurve.lcredsk; + //%%%%%%%%%%%%%%%%%%%%%% + + lshape->setCurve (pp->labCurve.lcurve); + ashape->setCurve (pp->labCurve.acurve); + bshape->setCurve (pp->labCurve.bcurve); + ccshape->setCurve (pp->labCurve.cccurve); + chshape->setCurve (pp->labCurve.chcurve); + lhshape->setCurve (pp->labCurve.lhcurve); + hhshape->setCurve (pp->labCurve.hhcurve); + lcshape->setCurve (pp->labCurve.lccurve); + clshape->setCurve (pp->labCurve.clcurve); + + queue_draw(); + + enableListener (); +} + +void LCurve::autoOpenCurve () { + // Open up the first curve if selected + bool active = lshape->openIfNonlinear(); + if (!active) ashape->openIfNonlinear(); + if (!active) bshape->openIfNonlinear(); + if (!active) ccshape->openIfNonlinear(); + if (!active) chshape->openIfNonlinear(); + if (!active) lhshape->openIfNonlinear(); + if (!active) hhshape->openIfNonlinear(); + if (!active) lcshape->openIfNonlinear(); + if (!active) clshape->openIfNonlinear(); +} + +void LCurve::setEditProvider (EditDataProvider *provider) { + lshape->setEditProvider(provider); + ccshape->setEditProvider(provider); + lcshape->setEditProvider(provider); + clshape->setEditProvider(provider); + lhshape->setEditProvider(provider); + chshape->setEditProvider(provider); + hhshape->setEditProvider(provider); + ashape->setEditProvider(provider); + bshape->setEditProvider(provider); + +} + + +void LCurve::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->labCurve.brightness = brightness->getValue (); + pp->labCurve.contrast = (int)contrast->getValue (); + pp->labCurve.chromaticity = (int)chromaticity->getValue (); + + //%%%%%%%%%%%%%%%%%%%%%% + pp->labCurve.avoidcolorshift = avoidcolorshift->get_active (); + pp->labCurve.lcredsk = lcredsk->get_active (); + + pp->labCurve.rstprotection = rstprotection->getValue (); + //%%%%%%%%%%%%%%%%%%%%%% + + pp->labCurve.lcurve = lshape->getCurve (); + pp->labCurve.acurve = ashape->getCurve (); + pp->labCurve.bcurve = bshape->getCurve (); + pp->labCurve.cccurve = ccshape->getCurve (); + pp->labCurve.chcurve = chshape->getCurve (); + pp->labCurve.lhcurve = lhshape->getCurve (); + pp->labCurve.hhcurve = hhshape->getCurve (); + pp->labCurve.lccurve = lcshape->getCurve (); + pp->labCurve.clcurve = clshape->getCurve (); + + if (pedited) { + pedited->labCurve.brightness = brightness->getEditedState (); + pedited->labCurve.contrast = contrast->getEditedState (); + pedited->labCurve.chromaticity = chromaticity->getEditedState (); + + //%%%%%%%%%%%%%%%%%%%%%% + pedited->labCurve.avoidcolorshift = !avoidcolorshift->get_inconsistent(); + pedited->labCurve.lcredsk = !lcredsk->get_inconsistent(); + + pedited->labCurve.rstprotection = rstprotection->getEditedState (); + //%%%%%%%%%%%%%%%%%%%%%% + + pedited->labCurve.lcurve = !lshape->isUnChanged (); + pedited->labCurve.acurve = !ashape->isUnChanged (); + pedited->labCurve.bcurve = !bshape->isUnChanged (); + pedited->labCurve.cccurve = !ccshape->isUnChanged (); + pedited->labCurve.chcurve = !chshape->isUnChanged (); + pedited->labCurve.lhcurve = !lhshape->isUnChanged (); + pedited->labCurve.hhcurve = !hhshape->isUnChanged (); + pedited->labCurve.lccurve = !lcshape->isUnChanged (); + pedited->labCurve.clcurve = !clshape->isUnChanged (); + } +} + +void LCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + brightness->setDefault (defParams->labCurve.brightness); + contrast->setDefault (defParams->labCurve.contrast); + chromaticity->setDefault (defParams->labCurve.chromaticity); + rstprotection->setDefault (defParams->labCurve.rstprotection); + + if (pedited) { + brightness->setDefaultEditedState (pedited->labCurve.brightness ? Edited : UnEdited); + contrast->setDefaultEditedState (pedited->labCurve.contrast ? Edited : UnEdited); + chromaticity->setDefaultEditedState (pedited->labCurve.chromaticity ? Edited : UnEdited); + rstprotection->setDefaultEditedState (pedited->labCurve.rstprotection ? Edited : UnEdited); + + } + else { + brightness->setDefaultEditedState (Irrelevant); + contrast->setDefaultEditedState (Irrelevant); + chromaticity->setDefaultEditedState (Irrelevant); + rstprotection->setDefaultEditedState (Irrelevant); + } +} + +//%%%%%%%%%%%%%%%%%%%%%% +//Color shift control changed +void LCurve::avoidcolorshift_toggled () { + + if (batchMode) { + if (avoidcolorshift->get_inconsistent()) { + avoidcolorshift->set_inconsistent (false); + acconn.block (true); + avoidcolorshift->set_active (false); + acconn.block (false); + } + else if (lastACVal) + avoidcolorshift->set_inconsistent (true); + + lastACVal = avoidcolorshift->get_active (); + } + + if (listener) { + if (avoidcolorshift->get_active ()) + listener->panelChanged (EvLAvoidColorShift, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvLAvoidColorShift, M("GENERAL_DISABLED")); + } +} + +void LCurve::lcredsk_toggled () { + + if (batchMode) { + if (lcredsk->get_inconsistent()) { + lcredsk->set_inconsistent (false); + lcconn.block (true); + lcredsk->set_active (false); + lcconn.block (false); + } + else if (lastLCVal) + lcredsk->set_inconsistent (true); + + lastLCVal = lcredsk->get_active (); + } + else { + lcshape->refresh(); + } + + if (listener) { + if (lcredsk->get_active ()) + listener->panelChanged (EvLLCredsk, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvLLCredsk, M("GENERAL_DISABLED")); + } +} + +//%%%%%%%%%%%%%%%%%%%%%% + +/* + * Curve listener + * + * If more than one curve has been added, the curve listener is automatically + * set to 'multi=true', and send a pointer of the modified curve in a parameter + */ +void LCurve::curveChanged (CurveEditor* ce) { + + if (listener) { + if (ce == lshape) + listener->panelChanged (EvLLCurve, M("HISTORY_CUSTOMCURVE")); + if (ce == ashape) + listener->panelChanged (EvLaCurve, M("HISTORY_CUSTOMCURVE")); + if (ce == bshape) + listener->panelChanged (EvLbCurve, M("HISTORY_CUSTOMCURVE")); + if (ce == ccshape) + listener->panelChanged (EvLCCCurve, M("HISTORY_CUSTOMCURVE")); + if (ce == chshape) + listener->panelChanged (EvLCHCurve, M("HISTORY_CUSTOMCURVE")); + if (ce == lhshape) + listener->panelChanged (EvLLHCurve, M("HISTORY_CUSTOMCURVE")); + if (ce == hhshape) + listener->panelChanged (EvLHHCurve, M("HISTORY_CUSTOMCURVE")); + if (ce == lcshape) + listener->panelChanged (EvLLCCurve, M("HISTORY_CUSTOMCURVE")); + if (ce == clshape) + listener->panelChanged (EvLCLCurve, M("HISTORY_CUSTOMCURVE")); + } +} + +void LCurve::adjusterChanged (Adjuster* a, double newval) { + + Glib::ustring costr; + if (a==brightness) + costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), a->getValue()); + else if (a==rstprotection) + costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(1), a->getValue()); + else + costr = Glib::ustring::format ((int)a->getValue()); + + if (a==brightness) { + if (listener) listener->panelChanged (EvLBrightness, costr); + } + else if (a==contrast) { + if (listener) listener->panelChanged (EvLContrast, costr); + } + else if (a==rstprotection) { + if (listener) listener->panelChanged (EvLRSTProtection, costr); + } + else if (a==chromaticity) { + if (multiImage) { + //if chromaticity==-100 (lowest value), we enter the B&W mode and avoid color shift and rstprotection has no effect + rstprotection->set_sensitive( true ); + avoidcolorshift->set_sensitive( true ); + lcredsk->set_sensitive( true ); + } + else { + //if chromaticity==-100 (lowest value), we enter the B&W mode and avoid color shift and rstprotection has no effect + rstprotection->set_sensitive( int(newval)> -100 );//no reason for grey rstprotection + avoidcolorshift->set_sensitive( int(newval)> -100 ); + lcredsk->set_sensitive( int(newval)> -100 ); + } + if (listener) listener->panelChanged (EvLSaturation, costr); + } +} + +void LCurve::colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller) { + + float R, G, B; + + if (elemType==ColorCaller::CCET_VERTICAL_BAR) + valY = 0.5; + + if (callerId == 1) { // ch - main curve + + Color::hsv2rgb01(float(valX), float(valY), 0.5f, R, G, B); + } + else if (callerId == 2) { // cc - bottom bar + + float value = (1.f - 0.7f) * float(valX) + 0.7f; + // whole hue range + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) + Color::hsv2rgb01(float(valY), float(valX), value, R, G, B); + } + else if (callerId == 3) { // lc - bottom bar + + float value = (1.f - 0.7f) * float(valX) + 0.7f; + if (lcredsk->get_active()) { + // skin range + // -0.1 rad < Hue < 1.6 rad + // Y axis / from 0.92 up to 0.14056 + float hue = (1.14056f - 0.92f) * float(valY) + 0.92f; + if (hue > 1.0f) hue -= 1.0f; + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) + Color::hsv2rgb01(hue, float(valX), value, R, G, B); + } + else { + // whole hue range + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) + Color::hsv2rgb01(float(valY), float(valX), value, R, G, B); + } + } + else if (callerId == 4) { // LH - bottom bar + Color::hsv2rgb01(float(valX), 0.5f, float(valY), R, G, B); + } + else if (callerId == 5) { // HH - bottom bar + float h = float((valY - 0.5) * 0.3 + valX); + if (h > 1.0f) + h -= 1.0f; + else if (h < 0.0f) + h += 1.0f; + Color::hsv2rgb01(h, 0.5f, 0.5f, R, G, B); + } + caller->ccRed = double(R); + caller->ccGreen = double(G); + caller->ccBlue = double(B); +} + +void LCurve::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + brightness->showEditedCB (); + contrast->showEditedCB (); + chromaticity->showEditedCB (); + rstprotection->showEditedCB (); + + curveEditorG->setBatchMode (batchMode); + lcshape->setBottomBarColorProvider(NULL, -1); + lcshape->setLeftBarColorProvider(NULL, -1); +} + + +void LCurve::updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve,/* LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma){ + + lshape->updateBackgroundHistogram (histLCurve); + ccshape->updateBackgroundHistogram (histCCurve); +// clshape->updateBackgroundHistogram (histCLurve); +// lcshape->updateBackgroundHistogram (histLLCurve); + +} + +void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd) { + + brightness->setAddMode(bradd); + contrast->setAddMode(contradd); + chromaticity->setAddMode(satadd); +} + +void LCurve::trimValues (rtengine::procparams::ProcParams* pp) { + + brightness->trimValue(pp->labCurve.brightness); + contrast->trimValue(pp->labCurve.contrast); + chromaticity->trimValue(pp->labCurve.chromaticity); +} diff --git a/rtgui/lensprofile.cc b/rtgui/lensprofile.cc index 703db4afc..68065739a 100644 --- a/rtgui/lensprofile.cc +++ b/rtgui/lensprofile.cc @@ -1,178 +1,178 @@ -/* -* This file is part of RawTherapee. -* -* Copyright (c) 2012 Oliver Duis -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -*/ -#include -#include "lensprofile.h" -#include "guiutils.h" -#include "../rtengine/safegtk.h" -#include "../rtengine/lcp.h" -#include -#include "rtimage.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -LensProfilePanel::LensProfilePanel () : FoldableToolPanel(this, "lensprof", M("TP_LENSPROFILE_LABEL")) -{ - hbLCPFile = Gtk::manage(new Gtk::HBox()); - - lLCPFileHead = Gtk::manage(new Gtk::Label(M("GENERAL_FILE"))); - hbLCPFile->pack_start(*lLCPFileHead, Gtk::PACK_SHRINK, 4); - - fcbLCPFile = Gtk::manage(new MyFileChooserButton(M("TP_LENSPROFILE_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); - - Gtk::FileFilter filterLCP; - filterLCP.set_name(M("FILECHOOSER_FILTER_LCP")); - filterLCP.add_pattern("*.lcp"); - filterLCP.add_pattern("*.LCP"); - fcbLCPFile->add_filter(filterLCP); - - Glib::ustring defDir=lcpStore->getDefaultCommonDirectory(); - if (!defDir.empty()) { -#ifdef WIN32 - fcbLCPFile->set_show_hidden(true); // ProgramData is hidden on Windows -#endif - fcbLCPFile->set_current_folder(defDir); - } - - hbLCPFile->pack_start(*fcbLCPFile); - - btnReset = Gtk::manage(new Gtk::Button()); - btnReset->set_image (*Gtk::manage(new RTImage ("gtk-cancel.png"))); - hbLCPFile->pack_start(*btnReset, Gtk::PACK_SHRINK, 4); - - pack_start(*hbLCPFile, Gtk::PACK_SHRINK, 4); - - ckbUseDist = Gtk::manage (new Gtk::CheckButton (M("TP_LENSPROFILE_USEDIST"))); - pack_start (*ckbUseDist, Gtk::PACK_SHRINK, 4); - ckbUseVign = Gtk::manage (new Gtk::CheckButton (M("TP_LENSPROFILE_USEVIGN"))); - pack_start (*ckbUseVign, Gtk::PACK_SHRINK, 4); - ckbUseCA = Gtk::manage (new Gtk::CheckButton (M("TP_LENSPROFILE_USECA"))); - pack_start (*ckbUseCA, Gtk::PACK_SHRINK, 4); - - conLCPFile = fcbLCPFile->signal_file_set().connect( sigc::mem_fun(*this, &LensProfilePanel::onLCPFileChanged), true); - btnReset->signal_clicked().connect( sigc::mem_fun(*this, &LensProfilePanel::onLCPFileReset), true); - ckbUseDist->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseDistChanged) ); - ckbUseVign->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseVignChanged) ); - ckbUseCA->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseCAChanged) ); - - allowFocusDep=true; -} - -void LensProfilePanel::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - - if (!pp->lensProf.lcpFile.empty() && lcpStore->isValidLCPFileName(pp->lensProf.lcpFile)) { - fcbLCPFile->set_filename (pp->lensProf.lcpFile); - updateDisabled(true); - } else { - Glib::ustring fname = fcbLCPFile->get_filename(); - if (!pp->lensProf.lcpFile.empty()) - fcbLCPFile->unselect_filename(fname); - else { - Glib::ustring lastFolder = fcbLCPFile->get_current_folder(); - fcbLCPFile->set_filename(""); - fcbLCPFile->set_current_folder(lastFolder); - } - updateDisabled(false); - } - - ckbUseDist->set_active (pp->lensProf.useDist); - ckbUseVign->set_active (pp->lensProf.useVign && isRaw); - ckbUseCA->set_active (pp->lensProf.useCA && isRaw); - - lcpFileChanged=useDistChanged=useVignChanged=useCAChanged=false; - - enableListener (); -} - -void LensProfilePanel::setRawMeta(bool raw, const rtengine::ImageMetaData* pMeta) { - if (!raw || pMeta->getFocusDist()<=0) { - disableListener(); - - // CA is very focus layer dependend, otherwise it might even worsen things - allowFocusDep=false; - ckbUseCA->set_active(false); - ckbUseCA->set_sensitive(false); - - enableListener(); - } - isRaw=raw; -} - -void LensProfilePanel::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - if (lcpStore->isValidLCPFileName(fcbLCPFile->get_filename())) - pp->lensProf.lcpFile = fcbLCPFile->get_filename(); - else - pp->lensProf.lcpFile = ""; - - pp->lensProf.useDist = ckbUseDist->get_active(); - pp->lensProf.useVign = ckbUseVign->get_active(); - pp->lensProf.useCA = ckbUseCA->get_active(); - - if (pedited) { - pedited->lensProf.lcpFile = lcpFileChanged; - pedited->lensProf.useDist = useDistChanged; - pedited->lensProf.useVign = useVignChanged; - pedited->lensProf.useCA = useCAChanged; - } -} - -void LensProfilePanel::onLCPFileChanged() -{ - lcpFileChanged=true; - updateDisabled(lcpStore->isValidLCPFileName(fcbLCPFile->get_filename())); - - if (listener) - listener->panelChanged (EvLCPFile, Glib::path_get_basename(fcbLCPFile->get_filename())); -} - -void LensProfilePanel::onLCPFileReset() -{ - lcpFileChanged=true; - - fcbLCPFile->unselect_filename(fcbLCPFile->get_filename()); - updateDisabled(false); - - if (listener) - listener->panelChanged (EvLCPFile, M("GENERAL_NONE")); -} - -void LensProfilePanel::onUseDistChanged() -{ - useDistChanged=true; - if (listener) listener->panelChanged (EvLCPUseDist, ckbUseDist->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); -} -void LensProfilePanel::onUseVignChanged() -{ - useVignChanged=true; - if (listener) listener->panelChanged (EvLCPUseVign, ckbUseVign->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); -} -void LensProfilePanel::onUseCAChanged() -{ - useCAChanged=true; - if (listener) listener->panelChanged (EvLCPUseCA, ckbUseCA->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); -} - -void LensProfilePanel::updateDisabled(bool enable) { - ckbUseDist->set_sensitive(enable); - ckbUseVign->set_sensitive(enable && isRaw); - ckbUseCA->set_sensitive(enable && allowFocusDep); -} +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2012 Oliver Duis +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ +#include +#include "lensprofile.h" +#include "guiutils.h" +#include "../rtengine/safegtk.h" +#include "../rtengine/lcp.h" +#include +#include "rtimage.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +LensProfilePanel::LensProfilePanel () : FoldableToolPanel(this, "lensprof", M("TP_LENSPROFILE_LABEL")) +{ + hbLCPFile = Gtk::manage(new Gtk::HBox()); + + lLCPFileHead = Gtk::manage(new Gtk::Label(M("GENERAL_FILE"))); + hbLCPFile->pack_start(*lLCPFileHead, Gtk::PACK_SHRINK, 4); + + fcbLCPFile = Gtk::manage(new MyFileChooserButton(M("TP_LENSPROFILE_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); + + Gtk::FileFilter filterLCP; + filterLCP.set_name(M("FILECHOOSER_FILTER_LCP")); + filterLCP.add_pattern("*.lcp"); + filterLCP.add_pattern("*.LCP"); + fcbLCPFile->add_filter(filterLCP); + + Glib::ustring defDir=lcpStore->getDefaultCommonDirectory(); + if (!defDir.empty()) { +#ifdef WIN32 + fcbLCPFile->set_show_hidden(true); // ProgramData is hidden on Windows +#endif + fcbLCPFile->set_current_folder(defDir); + } + + hbLCPFile->pack_start(*fcbLCPFile); + + btnReset = Gtk::manage(new Gtk::Button()); + btnReset->set_image (*Gtk::manage(new RTImage ("gtk-cancel.png"))); + hbLCPFile->pack_start(*btnReset, Gtk::PACK_SHRINK, 4); + + pack_start(*hbLCPFile, Gtk::PACK_SHRINK, 4); + + ckbUseDist = Gtk::manage (new Gtk::CheckButton (M("TP_LENSPROFILE_USEDIST"))); + pack_start (*ckbUseDist, Gtk::PACK_SHRINK, 4); + ckbUseVign = Gtk::manage (new Gtk::CheckButton (M("TP_LENSPROFILE_USEVIGN"))); + pack_start (*ckbUseVign, Gtk::PACK_SHRINK, 4); + ckbUseCA = Gtk::manage (new Gtk::CheckButton (M("TP_LENSPROFILE_USECA"))); + pack_start (*ckbUseCA, Gtk::PACK_SHRINK, 4); + + conLCPFile = fcbLCPFile->signal_file_set().connect( sigc::mem_fun(*this, &LensProfilePanel::onLCPFileChanged), true); + btnReset->signal_clicked().connect( sigc::mem_fun(*this, &LensProfilePanel::onLCPFileReset), true); + ckbUseDist->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseDistChanged) ); + ckbUseVign->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseVignChanged) ); + ckbUseCA->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseCAChanged) ); + + allowFocusDep=true; +} + +void LensProfilePanel::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + + if (!pp->lensProf.lcpFile.empty() && lcpStore->isValidLCPFileName(pp->lensProf.lcpFile)) { + fcbLCPFile->set_filename (pp->lensProf.lcpFile); + updateDisabled(true); + } else { + Glib::ustring fname = fcbLCPFile->get_filename(); + if (!pp->lensProf.lcpFile.empty()) + fcbLCPFile->unselect_filename(fname); + else { + Glib::ustring lastFolder = fcbLCPFile->get_current_folder(); + fcbLCPFile->set_filename(""); + fcbLCPFile->set_current_folder(lastFolder); + } + updateDisabled(false); + } + + ckbUseDist->set_active (pp->lensProf.useDist); + ckbUseVign->set_active (pp->lensProf.useVign && isRaw); + ckbUseCA->set_active (pp->lensProf.useCA && isRaw); + + lcpFileChanged=useDistChanged=useVignChanged=useCAChanged=false; + + enableListener (); +} + +void LensProfilePanel::setRawMeta(bool raw, const rtengine::ImageMetaData* pMeta) { + if (!raw || pMeta->getFocusDist()<=0) { + disableListener(); + + // CA is very focus layer dependend, otherwise it might even worsen things + allowFocusDep=false; + ckbUseCA->set_active(false); + ckbUseCA->set_sensitive(false); + + enableListener(); + } + isRaw=raw; +} + +void LensProfilePanel::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + if (lcpStore->isValidLCPFileName(fcbLCPFile->get_filename())) + pp->lensProf.lcpFile = fcbLCPFile->get_filename(); + else + pp->lensProf.lcpFile = ""; + + pp->lensProf.useDist = ckbUseDist->get_active(); + pp->lensProf.useVign = ckbUseVign->get_active(); + pp->lensProf.useCA = ckbUseCA->get_active(); + + if (pedited) { + pedited->lensProf.lcpFile = lcpFileChanged; + pedited->lensProf.useDist = useDistChanged; + pedited->lensProf.useVign = useVignChanged; + pedited->lensProf.useCA = useCAChanged; + } +} + +void LensProfilePanel::onLCPFileChanged() +{ + lcpFileChanged=true; + updateDisabled(lcpStore->isValidLCPFileName(fcbLCPFile->get_filename())); + + if (listener) + listener->panelChanged (EvLCPFile, Glib::path_get_basename(fcbLCPFile->get_filename())); +} + +void LensProfilePanel::onLCPFileReset() +{ + lcpFileChanged=true; + + fcbLCPFile->unselect_filename(fcbLCPFile->get_filename()); + updateDisabled(false); + + if (listener) + listener->panelChanged (EvLCPFile, M("GENERAL_NONE")); +} + +void LensProfilePanel::onUseDistChanged() +{ + useDistChanged=true; + if (listener) listener->panelChanged (EvLCPUseDist, ckbUseDist->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); +} +void LensProfilePanel::onUseVignChanged() +{ + useVignChanged=true; + if (listener) listener->panelChanged (EvLCPUseVign, ckbUseVign->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); +} +void LensProfilePanel::onUseCAChanged() +{ + useCAChanged=true; + if (listener) listener->panelChanged (EvLCPUseCA, ckbUseCA->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); +} + +void LensProfilePanel::updateDisabled(bool enable) { + ckbUseDist->set_sensitive(enable); + ckbUseVign->set_sensitive(enable && isRaw); + ckbUseCA->set_sensitive(enable && allowFocusDep); +} diff --git a/rtgui/lensprofile.h b/rtgui/lensprofile.h index 8aedb1aa6..8023786d2 100644 --- a/rtgui/lensprofile.h +++ b/rtgui/lensprofile.h @@ -1,56 +1,56 @@ -/* -* This file is part of RawTherapee. -* -* Copyright (c) 2012 Oliver Duis -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -*/ -#ifndef _LENSPROFILE_H_ -#define _LENSPROFILE_H_ - -#include -#include "toolpanel.h" -#include "guiutils.h" - -class LensProfilePanel : public ToolParamBlock, public FoldableToolPanel { - -protected: - - MyFileChooserButton *fcbLCPFile; - Gtk::CheckButton *ckbUseDist, *ckbUseVign, *ckbUseCA; - Gtk::HBox *hbLCPFile; - Gtk::Button *btnReset; - Gtk::Label *lLCPFileHead; - bool lcpFileChanged,useDistChanged,useVignChanged,useCAChanged; - sigc::connection conLCPFile, conUseDist, conUseVign, conUseCA; - void updateDisabled(bool enable); - bool allowFocusDep; - bool isRaw; - -public: - - LensProfilePanel (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setRawMeta (bool raw, const rtengine::ImageMetaData* pMeta); - - void onLCPFileChanged (); - void onLCPFileReset (); - void onUseDistChanged(); - void onUseVignChanged(); - void onUseCAChanged(); -}; - -#endif +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2012 Oliver Duis +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +*/ +#ifndef _LENSPROFILE_H_ +#define _LENSPROFILE_H_ + +#include +#include "toolpanel.h" +#include "guiutils.h" + +class LensProfilePanel : public ToolParamBlock, public FoldableToolPanel { + +protected: + + MyFileChooserButton *fcbLCPFile; + Gtk::CheckButton *ckbUseDist, *ckbUseVign, *ckbUseCA; + Gtk::HBox *hbLCPFile; + Gtk::Button *btnReset; + Gtk::Label *lLCPFileHead; + bool lcpFileChanged,useDistChanged,useVignChanged,useCAChanged; + sigc::connection conLCPFile, conUseDist, conUseVign, conUseCA; + void updateDisabled(bool enable); + bool allowFocusDep; + bool isRaw; + +public: + + LensProfilePanel (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setRawMeta (bool raw, const rtengine::ImageMetaData* pMeta); + + void onLCPFileChanged (); + void onLCPFileReset (); + void onUseDistChanged(); + void onUseVignChanged(); + void onUseCAChanged(); +}; + +#endif diff --git a/rtgui/main.cc b/rtgui/main.cc index b8daf5af5..e4e16be74 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -1,702 +1,702 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -// generated 2004/6/3 19:15:32 CEST by gabor@darkstar.(none) -// using glademm V2.5.0 -// -// newer (non customized) versions of this file go to raw.cc_new - -// This file is for your program, I won't touch it again! - -#ifdef __GNUC__ - #if defined(__FAST_MATH__) - #error Using the -ffast-math CFLAG is known to lead to problems. Disable it to compile RawTherapee. - #endif -#endif - -#include "config.h" -#include -#include -#include -#include -#include "rtwindow.h" -#include -#include -#include -#include "options.h" -#include "soundman.h" -#include "rtimage.h" -#include "version.h" -#include "extprog.h" - -#ifndef WIN32 -#include -#include -#include -#include -#else -#include -#include "conio.h" -#endif - -#include "../rtengine/safegtk.h" - -extern Options options; - -// stores path to data files -Glib::ustring argv0; -Glib::ustring creditsPath; -Glib::ustring licensePath; -Glib::ustring argv1; -bool simpleEditor; -Glib::Thread* mainThread; - - -// This recursive mutex will be used by gdk_threads_enter/leave instead of a simple mutex -#ifdef WIN32 -static Glib::RecMutex myGdkRecMutex; -#else -static Glib::Threads::RecMutex myGdkRecMutex; -#endif - -static void myGdkLockEnter() { myGdkRecMutex.lock(); } -static void myGdkLockLeave() { - // Automatic gdk_flush for non main tread - #if AUTO_GDK_FLUSH - if (Glib::Thread::self() != mainThread) { - gdk_flush(); - } - #endif - myGdkRecMutex.unlock(); -} - -/* Process line command options - * Returns - * 0 if process in batch has executed - * 1 to start GUI (with a dir or file option) - * 2 to start GUI because no files found - * -1 if there is an error in parameters - * -2 if an error occurred during processing - * -3 if at least one required procparam file was not found */ -int processLineParams( int argc, char **argv ); - -int main(int argc, char **argv) -{ - setlocale(LC_ALL,""); - setlocale(LC_NUMERIC, "C"); // to set decimal point to "." - // Uncomment the following line if you want to use the "--g-fatal-warnings" command line flag - //gtk_init (&argc, &argv); - - Glib::thread_init(); - gdk_threads_set_lock_functions(G_CALLBACK(myGdkLockEnter), (G_CALLBACK(myGdkLockLeave))); - gdk_threads_init(); - Gio::init (); - -#ifdef BUILD_BUNDLE - char exname[512] = {0}; - Glib::ustring exePath; - // get the path where the rawtherapee executable is stored - #ifdef WIN32 - WCHAR exnameU[512] = {0}; - GetModuleFileNameW (NULL, exnameU, 512); - WideCharToMultiByte(CP_UTF8,0,exnameU,-1,exname,512,0,0 ); - #else - if (readlink("/proc/self/exe", exname, 512) < 0) { - strncpy(exname, argv[0], 512); - } - #endif - exePath = Glib::path_get_dirname(exname); - - // set paths - if (Glib::path_is_absolute(DATA_SEARCH_PATH)) { - argv0 = DATA_SEARCH_PATH; - } else { - argv0 = Glib::build_filename(exePath, DATA_SEARCH_PATH); - } - if (Glib::path_is_absolute(CREDITS_SEARCH_PATH)) { - creditsPath = CREDITS_SEARCH_PATH; - } else { - creditsPath = Glib::build_filename(exePath, CREDITS_SEARCH_PATH); - } - if (Glib::path_is_absolute(LICENCE_SEARCH_PATH)) { - licensePath = LICENCE_SEARCH_PATH; - } else { - licensePath = Glib::build_filename(exePath, LICENCE_SEARCH_PATH); - } -#else - argv0 = DATA_SEARCH_PATH; - creditsPath = CREDITS_SEARCH_PATH; - licensePath = LICENCE_SEARCH_PATH; -#endif - - mainThread = Glib::Thread::self(); - - if (!Options::load ()) { - Gtk::Main m(&argc, &argv); - Gtk::MessageDialog msgd ("Fatal error!\nThe RT_SETTINGS and/or RT_PATH environment variables are set, but use a relative path. The path must be absolute!", true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); - msgd.run (); - return -2; - } - - extProgStore->init(); - SoundManager::init(); - -#ifdef WIN32 - bool consoleOpened = false; - - if (argc>1 || options.rtSettings.verbose){ - if(options.rtSettings.verbose || ( !safe_file_test( safe_filename_to_utf8(argv[1]), Glib::FILE_TEST_EXISTS ) && !safe_file_test( safe_filename_to_utf8(argv[1]), Glib::FILE_TEST_IS_DIR ))) { - bool stdoutRedirectedtoFile = (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == 0x0001); - bool stderrRedirectedtoFile = (GetFileType(GetStdHandle(STD_ERROR_HANDLE)) == 0x0001); - // no console, if stdout and stderr both are redirected to file - if( !(stdoutRedirectedtoFile && stderrRedirectedtoFile)) { - // check if parameter -w was passed. - // We have to do that in this step, because it controls whether to open a console to show the output of following steps - bool Console = true; - for(int i=1;i1 || options.rtSettings.verbose){ - // printing RT's version in all case, particularly useful for the 'verbose' mode, but also for the batch processing - std::cout << "RawTherapee, version " << VERSION << std::endl; - std::cout << "WARNING: closing this window will close RawTherapee!" << std::endl << std::endl; - if (argc>1){ - int ret = processLineParams( argc, argv); - if( ret <= 0 ) - return ret; - } - } -#endif - - if( !options.rtSettings.verbose ) - TIFFSetWarningHandler(NULL); // avoid annoying message boxes - -#ifndef WIN32 - // Move the old path to the new one if the new does not exist - if (safe_file_test(Glib::build_filename(options.rtdir,"cache"), Glib::FILE_TEST_IS_DIR) && !safe_file_test(options.cacheBaseDir, Glib::FILE_TEST_IS_DIR)) - safe_g_rename(Glib::build_filename(options.rtdir,"cache"), options.cacheBaseDir); -#endif - - simpleEditor=false; - if( !argv1.empty() ) - if( safe_file_test(argv1, Glib::FILE_TEST_EXISTS) && !safe_file_test(argv1, Glib::FILE_TEST_IS_DIR)) - simpleEditor = true; - - if (!options.useSystemTheme) - { - std::vector rcfiles; - rcfiles.push_back (argv0+"/themes/"+options.theme+".gtkrc"); - if (options.slimUI) - rcfiles.push_back (argv0+"/themes/slim"); - // Set the font face and size - Gtk::RC::parse_string (Glib::ustring::compose( - "style \"clearlooks-default\" { font_name = \"%1\" }", options.font)); - Gtk::RC::set_default_files (rcfiles); - } - Gtk::Main m(&argc, &argv); - - Glib::ustring icon_path = Glib::build_filename(argv0,"images"); - Glib::RefPtr defaultIconTheme = Gtk::IconTheme::get_default(); - defaultIconTheme->append_search_path(icon_path); - - RTImage::setPaths(options); - MyExpander::init(); // has to stay AFTER RTImage::setPaths - -#ifndef WIN32 - // For an unknown reason, gtkmm 2.22 don't know the gtk-button-images property, while it exists in the documentation... - // Anyway, the problem was Linux only - static Glib::RefPtr settings = Gtk::Settings::get_default(); - if (settings) - settings->property_gtk_button_images().set_value(true); - else - printf("Error: no default settings to update!\n"); -#endif - - gdk_threads_enter (); - RTWindow *rtWindow = new class RTWindow(); - - // alerting users if the default raw and image profiles are missing - if (options.is_defProfRawMissing()) { - Gtk::MessageDialog msgd (Glib::ustring::compose(M("OPTIONS_DEFRAW_MISSING"), options.defProfRaw), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); - msgd.run (); - } - if (options.is_defProfImgMissing()) { - Gtk::MessageDialog msgd (Glib::ustring::compose(M("OPTIONS_DEFIMG_MISSING"), options.defProfImg), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); - msgd.run (); - } - - // opening the main window - m.run(*rtWindow); - - gdk_threads_leave (); - delete rtWindow; - rtengine::cleanup(); - -#ifdef WIN32 - if (consoleOpened) { - printf("Press any key to exit RawTherapee\n"); - FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); - getch(); - } -#endif - - return 0; -} - -void deleteProcParams(std::vector &pparams) { - for (unsigned int i=0; ideleteInstance(); - delete pparams[i]; - pparams[i] = NULL; - } - return; -} - -int processLineParams( int argc, char **argv ) -{ - rtengine::procparams::PartialProfile *rawParams=NULL, *imgParams=NULL; - std::vector inputFiles; - Glib::ustring outputPath = ""; - std::vector processingParams; - bool outputDirectory=false; - bool overwriteFiles=false; - bool sideProcParams=false; - bool copyParamsFile=false; - bool skipIfNoSidecar=false; - bool useDefault=false; - unsigned int sideCarFilePos = 0; - int compression=92; - int subsampling=3; - int bits=-1; - std::string outputType = ""; - unsigned errors=0; - for( int iArg=1; iArgload ( fname ))) { - processingParams.push_back(currentParams); - } - else { - std::cerr << "Error: \""<< fname <<"\" not found" << std::endl; - deleteProcParams(processingParams); - return -3; - } - } - break; - case 'S': - skipIfNoSidecar=true; - case 's': // Processing params next to file (file extension appended) - sideProcParams = true; - sideCarFilePos = processingParams.size(); - break; - case 'd': - useDefault = true; - break; - case 'Y': - overwriteFiles =true; - break; - case 'j': - if (strlen(argv[iArg]) > 2 && argv[iArg][2] == 's') { - if (strlen(argv[iArg])==3) { - std::cerr << "Error: the -js switch requires a mandatory value!" << std::endl; - deleteProcParams(processingParams); - return -3; - } - // looking for the subsampling parameter - sscanf(&argv[iArg][3],"%d",&subsampling); - if (subsampling < 1 || subsampling > 3) { - std::cerr << "Error: the value accompanying the -js switch has to be in the [1-3] range!" << std::endl; - deleteProcParams(processingParams); - return -3; - } - } - else { - outputType = "jpg"; - sscanf(&argv[iArg][2],"%d",&compression); - if (compression < 0 || compression > 100) { - std::cerr << "Error: the value accompanying the -j switch has to be in the [0-100] range!" << std::endl; - deleteProcParams(processingParams); - return -3; - } - } - break; - case 'b': - sscanf(&argv[iArg][2],"%d",&bits); - if (bits != 8 && bits != 16) - { - std::cerr << "Error: specify -b8 for 8-bit or -b16 for 16-bit output." << std::endl; - deleteProcParams(processingParams); - return -3; - } - break; - case 't': - outputType = "tif"; - compression = ((argv[iArg][2]!='z')?0:1); - break; - case 'n': - outputType = "png"; - compression = -1; - break; - case 'c': // MUST be last option - while( iArg+1 names; - Glib::RefPtr dir = Gio::File::create_for_path ( argv[iArg] ); - safe_build_file_list (dir, names, argv[iArg] ); - for(size_t iFile=0; iFile< names.size(); iFile++ ){ - if( !safe_file_test( names[iFile] , Glib::FILE_TEST_IS_DIR)){ - // skip files without extension and without sidecar files - Glib::ustring s(names[iFile]); - Glib::ustring::size_type ext= s.find_last_of('.'); - if( Glib::ustring::npos == ext ) - continue; - if( ! s.substr(ext).compare( paramFileExtension )) - continue; - inputFiles.push_back( names[iFile] ); - } - } - }else{ - inputFiles.push_back( safe_filename_to_utf8 (argv[iArg]) ); - } - } - break; -#ifdef WIN32 - case 'w': // This case is handled outside this function - break; -#endif - case 'h': - case '?': - default: - { - Glib::ustring pparamsExt = paramFileExtension.substr(1); - std::cout << " indicate parameters you can change." << std::endl; - std::cout << "[Square brackets] mean the parameter is not mandatory." << std::endl; - std::cout << "The pipe symbol | indicates a choice of one or the other." << std::endl; - std::cout << "The dash symbol - denotes a range of possible values from one to the other." << std::endl; - cout << std::endl; - std::cout << "Usage:" << std::endl; - std::cout << " " << Glib::path_get_basename(argv[0]) << " Start File Browser inside directory." << std::endl; - std::cout << " " << Glib::path_get_basename(argv[0]) << " Start Image Editor with file." << std::endl; - std::cout << " " << Glib::path_get_basename(argv[0]) << " -c | Convert files in batch with default parameters." << std::endl << std::endl; -#ifdef WIN32 - std::cout << " -w Do not open the Windows console" << std::endl; -#endif - std::cout << "Other options used with -c (-c must be the last option):" << std::endl; - std::cout << Glib::path_get_basename(argv[0]) << " [-o |-O ] [-s|-S] [-p ] [-d] [-j[1-100] [-js<1-3>]|[-b<8|16>] <[-t[z] | [-n]]] [-Y] -c " << std::endl; - std::cout << " -o | Select output file or directory." << std::endl; - std::cout << " -O | Select output file or directory and copy " << pparamsExt << " file into it." << std::endl; - std::cout << " -s Include the " << pparamsExt << " file next to the input file (with the same" << std::endl; - std::cout << " name) to build the image parameters," << std::endl; - std::cout << " e.g. for photo.raw there should be a photo.raw." << pparamsExt << " file in" << std::endl; - std::cout << " the same directory. If the file does not exist, internal" << std::endl; - std::cout << " default (neutral) values (not those in Default." << pparamsExt << ") will be" << std::endl; - std::cout << " used." << std::endl; - std::cout << " -S Like -s but skip if the " << pparamsExt << " file does not exist." << std::endl; - std::cout << " -p Specify " << pparamsExt << " file to be used for all conversions." << std::endl; - std::cout << " You can specify as many -p options as you like (see" << std::endl; - std::cout << " description below)." << std::endl; - std::cout << " -d Use the default raw or non-raw " << pparamsExt << " file as set in" << std::endl; - std::cout << " Preferences > Image Processing > Default Processing Profile" << std::endl; - std::cout << " -j[1-100] Specify output to be JPEG (on by default). Optionally add" << std::endl; - std::cout << " compression 1-100 (default value: 92)." << std::endl; - std::cout << " -js<1-3> Specify the JPEG subsampling parameter, where:" << std::endl; - std::cout << " 1 = Best compression: 2x2, 1x1, 1x1 (4:1:1) - default of the JPEG library" << std::endl; - std::cout << " 2 = Widely used normal ratio: 2x1, 1x1, 1x1 (4:2:2)" << std::endl; - std::cout << " 3 = Best quality: 1x1, 1x1, 1x1 (4:4:4)" << std::endl; - std::cout << " -b<8|16> Specify bit depth per channel (only applies to TIFF and PNG output)." << std::endl; - std::cout << " -t[z] Specify output to be TIFF (16-bit if -b8 is not set)." << std::endl; - std::cout << " Uncompressed by default, or ZIP compression with 'z'" << std::endl; - std::cout << " -n Specify output to be compressed PNG (16-bit if -b8 is not set)." << std::endl; - std::cout << " -Y Overwrite output if present." << std::endl<load(profPath==DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfRaw.substr(5) + paramFileExtension))) { - std::cerr << "Error: default raw processing profile not found" << std::endl; - rawParams->deleteInstance(); - delete rawParams; - deleteProcParams(processingParams); - return -3; - } - imgParams = new rtengine::procparams::PartialProfile(true); - profPath = options.findProfilePath(options.defProfImg); - if (options.is_defProfImgMissing() || profPath.empty() || imgParams->load(profPath==DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfImg.substr(5) + paramFileExtension))) { - std::cerr << "Error: default non-raw processing profile not found" << std::endl; - imgParams->deleteInstance(); - delete imgParams; - rawParams->deleteInstance(); - delete rawParams; - deleteProcParams(processingParams); - return -3; - } - } - - for( size_t iFile=0; iFile< inputFiles.size(); iFile++){ - - // Has to be reinstanciated at each profile to have a ProcParams object with default values - rtengine::procparams::ProcParams currentParams; - - Glib::ustring inputFile = inputFiles[iFile]; - std::cout << "Processing: " << inputFile << std::endl; - - rtengine::InitialImage* ii=NULL; - rtengine::ProcessingJob* job =NULL; - int errorCode; - bool isRaw=false; - - Glib::ustring outputFile; - if( outputType.empty() ) - outputType = "jpg"; - if( outputPath.empty() ){ - Glib::ustring s = inputFile; - Glib::ustring::size_type ext= s.find_last_of('.'); - outputFile = s.substr(0,ext)+ "." + outputType; - }else if( outputDirectory ){ - Glib::ustring s = Glib::path_get_basename( inputFile ); - Glib::ustring::size_type ext= s.find_last_of('.'); - outputFile = outputPath + "/" + s.substr(0,ext) + "." + outputType; - }else{ - Glib::ustring s = outputPath; - Glib::ustring::size_type ext= s.find_last_of('.'); - outputFile = s.substr(0,ext) + "." + outputType; - } - if( inputFile == outputFile){ - std::cerr << "Cannot overwrite: " << inputFile << std::endl; - continue; - } - if( !overwriteFiles && safe_file_test( outputFile , Glib::FILE_TEST_EXISTS ) ){ - std::cerr << outputFile <<" already exists: use -Y option to overwrite. This image has been skipped." << std::endl; - continue; - } - - // Load the image - isRaw = true; - Glib::ustring ext = getExtension (inputFile); - if (ext.lowercase()=="jpg" || ext.lowercase()=="jpeg" || ext.lowercase()=="tif" || ext.lowercase()=="tiff" || ext.lowercase()=="png") - isRaw = false; - - ii = rtengine::InitialImage::load ( inputFile, isRaw, &errorCode, NULL ); - if (!ii) { - errors++; - std::cerr << "Error loading file: "<< inputFile << std::endl; - continue; - } - - if (useDefault) { - if (isRaw) { - std::cout << " Merging default raw processing profile" << std::endl; - rawParams->applyTo(¤tParams); - } - else { - std::cout << " Merging default non-raw processing profile" << std::endl; - imgParams->applyTo(¤tParams); - } - } - - bool sideCarFound = false; - unsigned int i=0; - // Iterate the procparams file list in order to build the final ProcParams - do { - if (sideProcParams && i==sideCarFilePos) { - // using the sidecar file - Glib::ustring sideProcessingParams = inputFile + paramFileExtension; - // the "load" method don't reset the procparams values anymore, so values found in the procparam file override the one of currentParams - if( !safe_file_test( sideProcessingParams, Glib::FILE_TEST_EXISTS ) || currentParams.load ( sideProcessingParams )) - std::cerr << "Warning: sidecar file requested but not found for: "<< sideProcessingParams << std::endl; - else { - sideCarFound = true; - std::cout << " Merging sidecar procparams" << std::endl; - } - } - if( processingParams.size()>i ) { - std::cout << " Merging procparams #" << i << std::endl; - processingParams[i]->applyTo(¤tParams); - } - i++; - } while (i < processingParams.size()+(sideProcParams?1:0)); - - if( sideProcParams && !sideCarFound && skipIfNoSidecar ){ - delete ii; - errors++; - std::cerr << "Error: no sidecar procparams found for: "<< inputFile << std::endl; - continue; - } - - job = rtengine::ProcessingJob::create (ii, currentParams); - if( !job ){ - errors++; - std::cerr << "Error creating processing for: "<< inputFile << std::endl; - ii->decreaseRef(); - continue; - } - - // Process image - rtengine::IImage16* resultImage = rtengine::processImage (job, errorCode, NULL, options.tunnelMetaData); - if( !resultImage ){ - errors++; - std::cerr << "Error processing: "<< inputFile << std::endl; - rtengine::ProcessingJob::destroy( job ); - continue; - } - // save image to disk - if( outputType=="jpg" ) - errorCode = resultImage->saveAsJPEG( outputFile, compression, subsampling ); - else if( outputType=="tif" ) - errorCode = resultImage->saveAsTIFF( outputFile, bits, compression==0 ); - else if( outputType=="png" ) - errorCode = resultImage->saveAsPNG( outputFile,compression, bits ); - else - errorCode = resultImage->saveToFile (outputFile); - - if(errorCode){ - errors++; - std::cerr << "Error saving to: "<< outputFile << std::endl; - }else{ - if( copyParamsFile ){ - Glib::ustring outputProcessingParams = outputFile + paramFileExtension; - currentParams.save( outputProcessingParams ); - } - } - - ii->decreaseRef(); - resultImage->free(); - } - - if (imgParams) { imgParams->deleteInstance(); delete imgParams; } - if (rawParams) { rawParams->deleteInstance(); delete rawParams; } - deleteProcParams(processingParams); - - return errors>0?-2:0; -} - +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +// generated 2004/6/3 19:15:32 CEST by gabor@darkstar.(none) +// using glademm V2.5.0 +// +// newer (non customized) versions of this file go to raw.cc_new + +// This file is for your program, I won't touch it again! + +#ifdef __GNUC__ + #if defined(__FAST_MATH__) + #error Using the -ffast-math CFLAG is known to lead to problems. Disable it to compile RawTherapee. + #endif +#endif + +#include "config.h" +#include +#include +#include +#include +#include "rtwindow.h" +#include +#include +#include +#include "options.h" +#include "soundman.h" +#include "rtimage.h" +#include "version.h" +#include "extprog.h" + +#ifndef WIN32 +#include +#include +#include +#include +#else +#include +#include "conio.h" +#endif + +#include "../rtengine/safegtk.h" + +extern Options options; + +// stores path to data files +Glib::ustring argv0; +Glib::ustring creditsPath; +Glib::ustring licensePath; +Glib::ustring argv1; +bool simpleEditor; +Glib::Thread* mainThread; + + +// This recursive mutex will be used by gdk_threads_enter/leave instead of a simple mutex +#ifdef WIN32 +static Glib::RecMutex myGdkRecMutex; +#else +static Glib::Threads::RecMutex myGdkRecMutex; +#endif + +static void myGdkLockEnter() { myGdkRecMutex.lock(); } +static void myGdkLockLeave() { + // Automatic gdk_flush for non main tread + #if AUTO_GDK_FLUSH + if (Glib::Thread::self() != mainThread) { + gdk_flush(); + } + #endif + myGdkRecMutex.unlock(); +} + +/* Process line command options + * Returns + * 0 if process in batch has executed + * 1 to start GUI (with a dir or file option) + * 2 to start GUI because no files found + * -1 if there is an error in parameters + * -2 if an error occurred during processing + * -3 if at least one required procparam file was not found */ +int processLineParams( int argc, char **argv ); + +int main(int argc, char **argv) +{ + setlocale(LC_ALL,""); + setlocale(LC_NUMERIC, "C"); // to set decimal point to "." + // Uncomment the following line if you want to use the "--g-fatal-warnings" command line flag + //gtk_init (&argc, &argv); + + Glib::thread_init(); + gdk_threads_set_lock_functions(G_CALLBACK(myGdkLockEnter), (G_CALLBACK(myGdkLockLeave))); + gdk_threads_init(); + Gio::init (); + +#ifdef BUILD_BUNDLE + char exname[512] = {0}; + Glib::ustring exePath; + // get the path where the rawtherapee executable is stored + #ifdef WIN32 + WCHAR exnameU[512] = {0}; + GetModuleFileNameW (NULL, exnameU, 512); + WideCharToMultiByte(CP_UTF8,0,exnameU,-1,exname,512,0,0 ); + #else + if (readlink("/proc/self/exe", exname, 512) < 0) { + strncpy(exname, argv[0], 512); + } + #endif + exePath = Glib::path_get_dirname(exname); + + // set paths + if (Glib::path_is_absolute(DATA_SEARCH_PATH)) { + argv0 = DATA_SEARCH_PATH; + } else { + argv0 = Glib::build_filename(exePath, DATA_SEARCH_PATH); + } + if (Glib::path_is_absolute(CREDITS_SEARCH_PATH)) { + creditsPath = CREDITS_SEARCH_PATH; + } else { + creditsPath = Glib::build_filename(exePath, CREDITS_SEARCH_PATH); + } + if (Glib::path_is_absolute(LICENCE_SEARCH_PATH)) { + licensePath = LICENCE_SEARCH_PATH; + } else { + licensePath = Glib::build_filename(exePath, LICENCE_SEARCH_PATH); + } +#else + argv0 = DATA_SEARCH_PATH; + creditsPath = CREDITS_SEARCH_PATH; + licensePath = LICENCE_SEARCH_PATH; +#endif + + mainThread = Glib::Thread::self(); + + if (!Options::load ()) { + Gtk::Main m(&argc, &argv); + Gtk::MessageDialog msgd ("Fatal error!\nThe RT_SETTINGS and/or RT_PATH environment variables are set, but use a relative path. The path must be absolute!", true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd.run (); + return -2; + } + + extProgStore->init(); + SoundManager::init(); + +#ifdef WIN32 + bool consoleOpened = false; + + if (argc>1 || options.rtSettings.verbose){ + if(options.rtSettings.verbose || ( !safe_file_test( safe_filename_to_utf8(argv[1]), Glib::FILE_TEST_EXISTS ) && !safe_file_test( safe_filename_to_utf8(argv[1]), Glib::FILE_TEST_IS_DIR ))) { + bool stdoutRedirectedtoFile = (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == 0x0001); + bool stderrRedirectedtoFile = (GetFileType(GetStdHandle(STD_ERROR_HANDLE)) == 0x0001); + // no console, if stdout and stderr both are redirected to file + if( !(stdoutRedirectedtoFile && stderrRedirectedtoFile)) { + // check if parameter -w was passed. + // We have to do that in this step, because it controls whether to open a console to show the output of following steps + bool Console = true; + for(int i=1;i1 || options.rtSettings.verbose){ + // printing RT's version in all case, particularly useful for the 'verbose' mode, but also for the batch processing + std::cout << "RawTherapee, version " << VERSION << std::endl; + std::cout << "WARNING: closing this window will close RawTherapee!" << std::endl << std::endl; + if (argc>1){ + int ret = processLineParams( argc, argv); + if( ret <= 0 ) + return ret; + } + } +#endif + + if( !options.rtSettings.verbose ) + TIFFSetWarningHandler(NULL); // avoid annoying message boxes + +#ifndef WIN32 + // Move the old path to the new one if the new does not exist + if (safe_file_test(Glib::build_filename(options.rtdir,"cache"), Glib::FILE_TEST_IS_DIR) && !safe_file_test(options.cacheBaseDir, Glib::FILE_TEST_IS_DIR)) + safe_g_rename(Glib::build_filename(options.rtdir,"cache"), options.cacheBaseDir); +#endif + + simpleEditor=false; + if( !argv1.empty() ) + if( safe_file_test(argv1, Glib::FILE_TEST_EXISTS) && !safe_file_test(argv1, Glib::FILE_TEST_IS_DIR)) + simpleEditor = true; + + if (!options.useSystemTheme) + { + std::vector rcfiles; + rcfiles.push_back (argv0+"/themes/"+options.theme+".gtkrc"); + if (options.slimUI) + rcfiles.push_back (argv0+"/themes/slim"); + // Set the font face and size + Gtk::RC::parse_string (Glib::ustring::compose( + "style \"clearlooks-default\" { font_name = \"%1\" }", options.font)); + Gtk::RC::set_default_files (rcfiles); + } + Gtk::Main m(&argc, &argv); + + Glib::ustring icon_path = Glib::build_filename(argv0,"images"); + Glib::RefPtr defaultIconTheme = Gtk::IconTheme::get_default(); + defaultIconTheme->append_search_path(icon_path); + + RTImage::setPaths(options); + MyExpander::init(); // has to stay AFTER RTImage::setPaths + +#ifndef WIN32 + // For an unknown reason, gtkmm 2.22 don't know the gtk-button-images property, while it exists in the documentation... + // Anyway, the problem was Linux only + static Glib::RefPtr settings = Gtk::Settings::get_default(); + if (settings) + settings->property_gtk_button_images().set_value(true); + else + printf("Error: no default settings to update!\n"); +#endif + + gdk_threads_enter (); + RTWindow *rtWindow = new class RTWindow(); + + // alerting users if the default raw and image profiles are missing + if (options.is_defProfRawMissing()) { + Gtk::MessageDialog msgd (Glib::ustring::compose(M("OPTIONS_DEFRAW_MISSING"), options.defProfRaw), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd.run (); + } + if (options.is_defProfImgMissing()) { + Gtk::MessageDialog msgd (Glib::ustring::compose(M("OPTIONS_DEFIMG_MISSING"), options.defProfImg), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + msgd.run (); + } + + // opening the main window + m.run(*rtWindow); + + gdk_threads_leave (); + delete rtWindow; + rtengine::cleanup(); + +#ifdef WIN32 + if (consoleOpened) { + printf("Press any key to exit RawTherapee\n"); + FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); + getch(); + } +#endif + + return 0; +} + +void deleteProcParams(std::vector &pparams) { + for (unsigned int i=0; ideleteInstance(); + delete pparams[i]; + pparams[i] = NULL; + } + return; +} + +int processLineParams( int argc, char **argv ) +{ + rtengine::procparams::PartialProfile *rawParams=NULL, *imgParams=NULL; + std::vector inputFiles; + Glib::ustring outputPath = ""; + std::vector processingParams; + bool outputDirectory=false; + bool overwriteFiles=false; + bool sideProcParams=false; + bool copyParamsFile=false; + bool skipIfNoSidecar=false; + bool useDefault=false; + unsigned int sideCarFilePos = 0; + int compression=92; + int subsampling=3; + int bits=-1; + std::string outputType = ""; + unsigned errors=0; + for( int iArg=1; iArgload ( fname ))) { + processingParams.push_back(currentParams); + } + else { + std::cerr << "Error: \""<< fname <<"\" not found" << std::endl; + deleteProcParams(processingParams); + return -3; + } + } + break; + case 'S': + skipIfNoSidecar=true; + case 's': // Processing params next to file (file extension appended) + sideProcParams = true; + sideCarFilePos = processingParams.size(); + break; + case 'd': + useDefault = true; + break; + case 'Y': + overwriteFiles =true; + break; + case 'j': + if (strlen(argv[iArg]) > 2 && argv[iArg][2] == 's') { + if (strlen(argv[iArg])==3) { + std::cerr << "Error: the -js switch requires a mandatory value!" << std::endl; + deleteProcParams(processingParams); + return -3; + } + // looking for the subsampling parameter + sscanf(&argv[iArg][3],"%d",&subsampling); + if (subsampling < 1 || subsampling > 3) { + std::cerr << "Error: the value accompanying the -js switch has to be in the [1-3] range!" << std::endl; + deleteProcParams(processingParams); + return -3; + } + } + else { + outputType = "jpg"; + sscanf(&argv[iArg][2],"%d",&compression); + if (compression < 0 || compression > 100) { + std::cerr << "Error: the value accompanying the -j switch has to be in the [0-100] range!" << std::endl; + deleteProcParams(processingParams); + return -3; + } + } + break; + case 'b': + sscanf(&argv[iArg][2],"%d",&bits); + if (bits != 8 && bits != 16) + { + std::cerr << "Error: specify -b8 for 8-bit or -b16 for 16-bit output." << std::endl; + deleteProcParams(processingParams); + return -3; + } + break; + case 't': + outputType = "tif"; + compression = ((argv[iArg][2]!='z')?0:1); + break; + case 'n': + outputType = "png"; + compression = -1; + break; + case 'c': // MUST be last option + while( iArg+1 names; + Glib::RefPtr dir = Gio::File::create_for_path ( argv[iArg] ); + safe_build_file_list (dir, names, argv[iArg] ); + for(size_t iFile=0; iFile< names.size(); iFile++ ){ + if( !safe_file_test( names[iFile] , Glib::FILE_TEST_IS_DIR)){ + // skip files without extension and without sidecar files + Glib::ustring s(names[iFile]); + Glib::ustring::size_type ext= s.find_last_of('.'); + if( Glib::ustring::npos == ext ) + continue; + if( ! s.substr(ext).compare( paramFileExtension )) + continue; + inputFiles.push_back( names[iFile] ); + } + } + }else{ + inputFiles.push_back( safe_filename_to_utf8 (argv[iArg]) ); + } + } + break; +#ifdef WIN32 + case 'w': // This case is handled outside this function + break; +#endif + case 'h': + case '?': + default: + { + Glib::ustring pparamsExt = paramFileExtension.substr(1); + std::cout << " indicate parameters you can change." << std::endl; + std::cout << "[Square brackets] mean the parameter is not mandatory." << std::endl; + std::cout << "The pipe symbol | indicates a choice of one or the other." << std::endl; + std::cout << "The dash symbol - denotes a range of possible values from one to the other." << std::endl; + cout << std::endl; + std::cout << "Usage:" << std::endl; + std::cout << " " << Glib::path_get_basename(argv[0]) << " Start File Browser inside directory." << std::endl; + std::cout << " " << Glib::path_get_basename(argv[0]) << " Start Image Editor with file." << std::endl; + std::cout << " " << Glib::path_get_basename(argv[0]) << " -c | Convert files in batch with default parameters." << std::endl << std::endl; +#ifdef WIN32 + std::cout << " -w Do not open the Windows console" << std::endl; +#endif + std::cout << "Other options used with -c (-c must be the last option):" << std::endl; + std::cout << Glib::path_get_basename(argv[0]) << " [-o |-O ] [-s|-S] [-p ] [-d] [-j[1-100] [-js<1-3>]|[-b<8|16>] <[-t[z] | [-n]]] [-Y] -c " << std::endl; + std::cout << " -o | Select output file or directory." << std::endl; + std::cout << " -O | Select output file or directory and copy " << pparamsExt << " file into it." << std::endl; + std::cout << " -s Include the " << pparamsExt << " file next to the input file (with the same" << std::endl; + std::cout << " name) to build the image parameters," << std::endl; + std::cout << " e.g. for photo.raw there should be a photo.raw." << pparamsExt << " file in" << std::endl; + std::cout << " the same directory. If the file does not exist, internal" << std::endl; + std::cout << " default (neutral) values (not those in Default." << pparamsExt << ") will be" << std::endl; + std::cout << " used." << std::endl; + std::cout << " -S Like -s but skip if the " << pparamsExt << " file does not exist." << std::endl; + std::cout << " -p Specify " << pparamsExt << " file to be used for all conversions." << std::endl; + std::cout << " You can specify as many -p options as you like (see" << std::endl; + std::cout << " description below)." << std::endl; + std::cout << " -d Use the default raw or non-raw " << pparamsExt << " file as set in" << std::endl; + std::cout << " Preferences > Image Processing > Default Processing Profile" << std::endl; + std::cout << " -j[1-100] Specify output to be JPEG (on by default). Optionally add" << std::endl; + std::cout << " compression 1-100 (default value: 92)." << std::endl; + std::cout << " -js<1-3> Specify the JPEG subsampling parameter, where:" << std::endl; + std::cout << " 1 = Best compression: 2x2, 1x1, 1x1 (4:1:1) - default of the JPEG library" << std::endl; + std::cout << " 2 = Widely used normal ratio: 2x1, 1x1, 1x1 (4:2:2)" << std::endl; + std::cout << " 3 = Best quality: 1x1, 1x1, 1x1 (4:4:4)" << std::endl; + std::cout << " -b<8|16> Specify bit depth per channel (only applies to TIFF and PNG output)." << std::endl; + std::cout << " -t[z] Specify output to be TIFF (16-bit if -b8 is not set)." << std::endl; + std::cout << " Uncompressed by default, or ZIP compression with 'z'" << std::endl; + std::cout << " -n Specify output to be compressed PNG (16-bit if -b8 is not set)." << std::endl; + std::cout << " -Y Overwrite output if present." << std::endl<load(profPath==DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfRaw.substr(5) + paramFileExtension))) { + std::cerr << "Error: default raw processing profile not found" << std::endl; + rawParams->deleteInstance(); + delete rawParams; + deleteProcParams(processingParams); + return -3; + } + imgParams = new rtengine::procparams::PartialProfile(true); + profPath = options.findProfilePath(options.defProfImg); + if (options.is_defProfImgMissing() || profPath.empty() || imgParams->load(profPath==DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(profPath, options.defProfImg.substr(5) + paramFileExtension))) { + std::cerr << "Error: default non-raw processing profile not found" << std::endl; + imgParams->deleteInstance(); + delete imgParams; + rawParams->deleteInstance(); + delete rawParams; + deleteProcParams(processingParams); + return -3; + } + } + + for( size_t iFile=0; iFile< inputFiles.size(); iFile++){ + + // Has to be reinstanciated at each profile to have a ProcParams object with default values + rtengine::procparams::ProcParams currentParams; + + Glib::ustring inputFile = inputFiles[iFile]; + std::cout << "Processing: " << inputFile << std::endl; + + rtengine::InitialImage* ii=NULL; + rtengine::ProcessingJob* job =NULL; + int errorCode; + bool isRaw=false; + + Glib::ustring outputFile; + if( outputType.empty() ) + outputType = "jpg"; + if( outputPath.empty() ){ + Glib::ustring s = inputFile; + Glib::ustring::size_type ext= s.find_last_of('.'); + outputFile = s.substr(0,ext)+ "." + outputType; + }else if( outputDirectory ){ + Glib::ustring s = Glib::path_get_basename( inputFile ); + Glib::ustring::size_type ext= s.find_last_of('.'); + outputFile = outputPath + "/" + s.substr(0,ext) + "." + outputType; + }else{ + Glib::ustring s = outputPath; + Glib::ustring::size_type ext= s.find_last_of('.'); + outputFile = s.substr(0,ext) + "." + outputType; + } + if( inputFile == outputFile){ + std::cerr << "Cannot overwrite: " << inputFile << std::endl; + continue; + } + if( !overwriteFiles && safe_file_test( outputFile , Glib::FILE_TEST_EXISTS ) ){ + std::cerr << outputFile <<" already exists: use -Y option to overwrite. This image has been skipped." << std::endl; + continue; + } + + // Load the image + isRaw = true; + Glib::ustring ext = getExtension (inputFile); + if (ext.lowercase()=="jpg" || ext.lowercase()=="jpeg" || ext.lowercase()=="tif" || ext.lowercase()=="tiff" || ext.lowercase()=="png") + isRaw = false; + + ii = rtengine::InitialImage::load ( inputFile, isRaw, &errorCode, NULL ); + if (!ii) { + errors++; + std::cerr << "Error loading file: "<< inputFile << std::endl; + continue; + } + + if (useDefault) { + if (isRaw) { + std::cout << " Merging default raw processing profile" << std::endl; + rawParams->applyTo(¤tParams); + } + else { + std::cout << " Merging default non-raw processing profile" << std::endl; + imgParams->applyTo(¤tParams); + } + } + + bool sideCarFound = false; + unsigned int i=0; + // Iterate the procparams file list in order to build the final ProcParams + do { + if (sideProcParams && i==sideCarFilePos) { + // using the sidecar file + Glib::ustring sideProcessingParams = inputFile + paramFileExtension; + // the "load" method don't reset the procparams values anymore, so values found in the procparam file override the one of currentParams + if( !safe_file_test( sideProcessingParams, Glib::FILE_TEST_EXISTS ) || currentParams.load ( sideProcessingParams )) + std::cerr << "Warning: sidecar file requested but not found for: "<< sideProcessingParams << std::endl; + else { + sideCarFound = true; + std::cout << " Merging sidecar procparams" << std::endl; + } + } + if( processingParams.size()>i ) { + std::cout << " Merging procparams #" << i << std::endl; + processingParams[i]->applyTo(¤tParams); + } + i++; + } while (i < processingParams.size()+(sideProcParams?1:0)); + + if( sideProcParams && !sideCarFound && skipIfNoSidecar ){ + delete ii; + errors++; + std::cerr << "Error: no sidecar procparams found for: "<< inputFile << std::endl; + continue; + } + + job = rtengine::ProcessingJob::create (ii, currentParams); + if( !job ){ + errors++; + std::cerr << "Error creating processing for: "<< inputFile << std::endl; + ii->decreaseRef(); + continue; + } + + // Process image + rtengine::IImage16* resultImage = rtengine::processImage (job, errorCode, NULL, options.tunnelMetaData); + if( !resultImage ){ + errors++; + std::cerr << "Error processing: "<< inputFile << std::endl; + rtengine::ProcessingJob::destroy( job ); + continue; + } + // save image to disk + if( outputType=="jpg" ) + errorCode = resultImage->saveAsJPEG( outputFile, compression, subsampling ); + else if( outputType=="tif" ) + errorCode = resultImage->saveAsTIFF( outputFile, bits, compression==0 ); + else if( outputType=="png" ) + errorCode = resultImage->saveAsPNG( outputFile,compression, bits ); + else + errorCode = resultImage->saveToFile (outputFile); + + if(errorCode){ + errors++; + std::cerr << "Error saving to: "<< outputFile << std::endl; + }else{ + if( copyParamsFile ){ + Glib::ustring outputProcessingParams = outputFile + paramFileExtension; + currentParams.save( outputProcessingParams ); + } + } + + ii->decreaseRef(); + resultImage->free(); + } + + if (imgParams) { imgParams->deleteInstance(); delete imgParams; } + if (rawParams) { rawParams->deleteInstance(); delete rawParams; } + deleteProcParams(processingParams); + + return errors>0?-2:0; +} + diff --git a/rtgui/mycurve.cc b/rtgui/mycurve.cc index 5301dda62..21eb4df80 100644 --- a/rtgui/mycurve.cc +++ b/rtgui/mycurve.cc @@ -1,143 +1,143 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "mycurve.h" -#include "../rtengine/curves.h" -#include -#include - -MyCurve::MyCurve () : pipetteR(-1.f), pipetteG(-1.f), pipetteB(-1.f), pipetteVal(-1.f), listener(NULL) { - - cursor_type = CSArrow; - graphX = get_allocation().get_width() - RADIUS * 2; - graphY = get_allocation().get_height() - RADIUS * 2; - prevGraphW = graphW; - prevGraphH = graphH; - buttonPressed = false; - snapTo = ST_None; - leftBar = NULL; - bottomBar = NULL; - colorProvider = NULL; - sized = RS_Pending; - snapToElmt = -100; - curveIsDirty = true; - edited_point = -1; - - set_extension_events(Gdk::EXTENSION_EVENTS_ALL); -#if defined (__APPLE__) - // Workaround: disabling POINTER_MOTION_HINT_MASK as for gtk 2.24.22 the get_pointer() function is buggy for quartz and modifier mask is not updated correctly. - // This workaround should be removed when bug is fixed in GTK2 or when migrating to GTK3 - add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK); -#else - add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK); -#endif - - mcih = new MyCurveIdleHelper; - mcih->myCurve = this; - mcih->destroyed = false; - mcih->pending = 0; -} - -MyCurve::~MyCurve () { - - if (mcih->pending) - mcih->destroyed = true; - else - delete mcih; -} - -int MyCurve::calcDimensions () { - int newRequestedW, newRequestedH; - - newRequestedW = newRequestedH = get_allocation().get_width(); - if (leftBar && !bottomBar) - newRequestedH -= getBarWidth() + CBAR_MARGIN - RADIUS; - if (!leftBar && bottomBar) - newRequestedH += getBarWidth() + CBAR_MARGIN - RADIUS; - - graphW = newRequestedW - RADIUS - (leftBar ? (getBarWidth()+CBAR_MARGIN) : RADIUS); - graphH = newRequestedH - RADIUS - (bottomBar ? (getBarWidth()+CBAR_MARGIN) : RADIUS); - graphX = newRequestedW - RADIUS - graphW; - graphY = RADIUS + graphH; - - return newRequestedH; -} - -void MyCurve::setColoredBar (ColoredBar *left, ColoredBar *bottom) { - leftBar = left; - bottomBar = bottom; -} - -void MyCurve::notifyListener () { - - if (listener) - listener->curveChanged (); -} - -bool MyCurve::snapCoordinateX(double testedVal, double realVal) { - - double dist = realVal - testedVal; - - if (dist < 0.) dist = -dist; - if (dist < snapToMinDistX) { - snapToMinDistX = dist; - snapToValX = testedVal; - return true; - } - return false; -} - -bool MyCurve::snapCoordinateY(double testedVal, double realVal) { - - double dist = realVal - testedVal; - - if (dist < 0.) dist = -dist; - if (dist < snapToMinDistY) { - snapToMinDistY = dist; - snapToValY = testedVal; - return true; - } - return false; -} - -float MyCurve::getVal(LUTf &curve, int x) { - if ((graphW-2) == curve.getSize()) { - return curve[x]; - } - else { - return curve.getVal01(float(x)/(graphW-3)); - } -} - -void MyCurve::on_style_changed (const Glib::RefPtr& style) { - setDirty(true); - queue_draw (); -} - -void MyCurve::refresh() { - if (leftBar != NULL) - leftBar->setDirty(true); - if (bottomBar != NULL) - bottomBar->setDirty(true); - - setDirty(true); - - Glib::RefPtr win = get_window(); - if (win) - win->invalidate(true); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "mycurve.h" +#include "../rtengine/curves.h" +#include +#include + +MyCurve::MyCurve () : pipetteR(-1.f), pipetteG(-1.f), pipetteB(-1.f), pipetteVal(-1.f), listener(NULL) { + + cursor_type = CSArrow; + graphX = get_allocation().get_width() - RADIUS * 2; + graphY = get_allocation().get_height() - RADIUS * 2; + prevGraphW = graphW; + prevGraphH = graphH; + buttonPressed = false; + snapTo = ST_None; + leftBar = NULL; + bottomBar = NULL; + colorProvider = NULL; + sized = RS_Pending; + snapToElmt = -100; + curveIsDirty = true; + edited_point = -1; + + set_extension_events(Gdk::EXTENSION_EVENTS_ALL); +#if defined (__APPLE__) + // Workaround: disabling POINTER_MOTION_HINT_MASK as for gtk 2.24.22 the get_pointer() function is buggy for quartz and modifier mask is not updated correctly. + // This workaround should be removed when bug is fixed in GTK2 or when migrating to GTK3 + add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK); +#else + add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK); +#endif + + mcih = new MyCurveIdleHelper; + mcih->myCurve = this; + mcih->destroyed = false; + mcih->pending = 0; +} + +MyCurve::~MyCurve () { + + if (mcih->pending) + mcih->destroyed = true; + else + delete mcih; +} + +int MyCurve::calcDimensions () { + int newRequestedW, newRequestedH; + + newRequestedW = newRequestedH = get_allocation().get_width(); + if (leftBar && !bottomBar) + newRequestedH -= getBarWidth() + CBAR_MARGIN - RADIUS; + if (!leftBar && bottomBar) + newRequestedH += getBarWidth() + CBAR_MARGIN - RADIUS; + + graphW = newRequestedW - RADIUS - (leftBar ? (getBarWidth()+CBAR_MARGIN) : RADIUS); + graphH = newRequestedH - RADIUS - (bottomBar ? (getBarWidth()+CBAR_MARGIN) : RADIUS); + graphX = newRequestedW - RADIUS - graphW; + graphY = RADIUS + graphH; + + return newRequestedH; +} + +void MyCurve::setColoredBar (ColoredBar *left, ColoredBar *bottom) { + leftBar = left; + bottomBar = bottom; +} + +void MyCurve::notifyListener () { + + if (listener) + listener->curveChanged (); +} + +bool MyCurve::snapCoordinateX(double testedVal, double realVal) { + + double dist = realVal - testedVal; + + if (dist < 0.) dist = -dist; + if (dist < snapToMinDistX) { + snapToMinDistX = dist; + snapToValX = testedVal; + return true; + } + return false; +} + +bool MyCurve::snapCoordinateY(double testedVal, double realVal) { + + double dist = realVal - testedVal; + + if (dist < 0.) dist = -dist; + if (dist < snapToMinDistY) { + snapToMinDistY = dist; + snapToValY = testedVal; + return true; + } + return false; +} + +float MyCurve::getVal(LUTf &curve, int x) { + if ((graphW-2) == curve.getSize()) { + return curve[x]; + } + else { + return curve.getVal01(float(x)/(graphW-3)); + } +} + +void MyCurve::on_style_changed (const Glib::RefPtr& style) { + setDirty(true); + queue_draw (); +} + +void MyCurve::refresh() { + if (leftBar != NULL) + leftBar->setDirty(true); + if (bottomBar != NULL) + bottomBar->setDirty(true); + + setDirty(true); + + Glib::RefPtr win = get_window(); + if (win) + win->invalidate(true); +} diff --git a/rtgui/myicon.rc b/rtgui/myicon.rc index b986cd1b6..94f2ab31a 100644 --- a/rtgui/myicon.rc +++ b/rtgui/myicon.rc @@ -1 +1 @@ -1 ICON "RT.ico" +1 ICON "RT.ico" diff --git a/rtgui/options.cc b/rtgui/options.cc index 4dcbfcd0b..7e62547f9 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -1,1094 +1,1094 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "options.h" -#include -#include -#include -#include "multilangmgr.h" -#include "../rtengine/safekeyfile.h" -#include "addsetids.h" -#include "guiutils.h" -#include "../rtengine/safegtk.h" -#include "version.h" - -#ifdef _OPENMP -#include -#endif - - - -#ifdef WIN32 -#include -// for GCC32 -#ifndef _WIN32_IE -#define _WIN32_IE 0x0600 -#endif -#include -#endif - -// User's settings directory, including images' profiles if used -Glib::ustring Options::rtdir; -// User's cached datas' directory -Glib::ustring Options::cacheBaseDir; - -Options options; -Glib::ustring versionString = VERSION; -Glib::ustring versionSuffixString = VERSION_SUFFIX; -Glib::ustring paramFileExtension = ".pp3"; - -Options::Options () { - - defProfRawMissing = false; - defProfImgMissing = false; - setDefaults (); -} - -const char *DefaultLanguage = "English (US)"; - -inline bool Options::checkProfilePath(Glib::ustring &path) { - if (path.empty()) - return false; - - Glib::ustring p = getUserProfilePath(); - if (!p.empty() && safe_file_test (path+paramFileExtension, Glib::FILE_TEST_EXISTS)) - return true; - - p = getGlobalProfilePath(); - if (!p.empty() && safe_file_test (path+paramFileExtension, Glib::FILE_TEST_EXISTS)) - return true; - else - return false; -} - -bool Options::checkDirPath(Glib::ustring &path, Glib::ustring errString) { - if (safe_file_test (path, Glib::FILE_TEST_EXISTS) && safe_file_test (path, Glib::FILE_TEST_IS_DIR)) - return true; - else { - if (!errString.empty()) printf("%s\n", errString.c_str()); - return false; - } -} - -void Options::updatePaths() { - - Glib::ustring tmpPath; - - userProfilePath = ""; - globalProfilePath = ""; - - if (Glib::path_is_absolute(profilePath)) { - // absolute path - if (!checkDirPath (profilePath, "")) { - safe_g_mkdir_with_parents (profilePath, 511); - if (!checkDirPath (profilePath, "")) // had problems with mkdir_with_parents return value on OS X, just check dir again - printf("Error: user's profiles' directory \"%s\" creation failed\n", profilePath.c_str()); - } - if (checkDirPath (profilePath, "Error: the specified user's profiles' path doesn't point to a directory or doesn't exist!\n")) { - if (multiUser) { - userProfilePath = profilePath; - tmpPath = Glib::build_filename(argv0, "profiles"); - if(checkDirPath (tmpPath, "Error: the global's profiles' path doesn't point to a directory or doesn't exist!\n")) { - if (userProfilePath != tmpPath) - globalProfilePath = tmpPath; - } - } - else { - globalProfilePath = profilePath; - } - } - else { - tmpPath = Glib::build_filename(argv0, "profiles"); - if(checkDirPath (tmpPath, "Error: the global's profiles' path doesn't point to a directory or doesn't exist!\n")) { - globalProfilePath = tmpPath; - } - } - } - else { - // relative paths - if (multiUser) { - tmpPath = Glib::build_filename(rtdir, profilePath); - if (!checkDirPath (tmpPath, "")) { - safe_g_mkdir_with_parents (tmpPath, 511); - if (!checkDirPath (tmpPath, "")) - printf("Error: user's profiles' directory \"%s\" creation failed\n", tmpPath.c_str()); - } - if(checkDirPath (tmpPath, "Error: the specified user's profiles' path doesn't point to a directory!\n")) { - userProfilePath = tmpPath; - } - tmpPath = Glib::build_filename(argv0, "profiles"); - if(checkDirPath (tmpPath, "Error: the specified user's profiles' path doesn't point to a directory or doesn't exist!\n")) { - globalProfilePath = tmpPath; - } - } - else { - // common directory - // directory name set in options is ignored, we use the default directory name - tmpPath = Glib::build_filename(argv0, "profiles"); - if(checkDirPath (tmpPath, "Error: no global profiles' directory found!\n")) { - globalProfilePath = tmpPath; - } - } - } - - Glib::ustring preferredPath = getPreferredProfilePath(); - // Paths are updated only if the user or global profile path is set - if (lastRgbCurvesDir.empty() || !safe_file_test (lastRgbCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastRgbCurvesDir, Glib::FILE_TEST_IS_DIR)) - lastRgbCurvesDir = preferredPath; - if (lastLabCurvesDir.empty() || !safe_file_test (lastLabCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastLabCurvesDir, Glib::FILE_TEST_IS_DIR)) - lastLabCurvesDir = preferredPath; - if (lastDenoiseCurvesDir.empty() || !safe_file_test (lastDenoiseCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastDenoiseCurvesDir, Glib::FILE_TEST_IS_DIR)) - lastDenoiseCurvesDir = preferredPath; - if (lastWaveletCurvesDir.empty() || !safe_file_test (lastWaveletCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastWaveletCurvesDir, Glib::FILE_TEST_IS_DIR)) - lastWaveletCurvesDir = preferredPath; - - if (lastPFCurvesDir.empty() || !safe_file_test (lastPFCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastPFCurvesDir, Glib::FILE_TEST_IS_DIR)) - lastPFCurvesDir = preferredPath; - if (lastHsvCurvesDir.empty() || !safe_file_test (lastHsvCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastHsvCurvesDir, Glib::FILE_TEST_IS_DIR)) - lastHsvCurvesDir = preferredPath; - if (lastToneCurvesDir.empty() || !safe_file_test (lastToneCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastToneCurvesDir, Glib::FILE_TEST_IS_DIR)) - lastToneCurvesDir = preferredPath; - if (lastProfilingReferenceDir.empty() || !safe_file_test (lastProfilingReferenceDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastProfilingReferenceDir, Glib::FILE_TEST_IS_DIR)) - lastProfilingReferenceDir = preferredPath; - if (lastVibranceCurvesDir.empty() || !safe_file_test (lastVibranceCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastVibranceCurvesDir, Glib::FILE_TEST_IS_DIR)) - lastVibranceCurvesDir = preferredPath; - if (loadSaveProfilePath.empty() || !safe_file_test (loadSaveProfilePath, Glib::FILE_TEST_EXISTS) || !safe_file_test (loadSaveProfilePath, Glib::FILE_TEST_IS_DIR)) - loadSaveProfilePath = preferredPath; - if (lastBWCurvesDir.empty() || !safe_file_test (lastBWCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastBWCurvesDir, Glib::FILE_TEST_IS_DIR)) - lastBWCurvesDir = preferredPath; - -} - -Glib::ustring Options::getPreferredProfilePath() { - if (!userProfilePath.empty()) - return userProfilePath; - else if (!globalProfilePath.empty()) - return globalProfilePath; - else - return ""; -} - -/** @brief Get the absolute path of the given filename or the "Neutral" special value - * - *@param profName path + filename of the procparam to look for. A filename without path can be provided for backward compatibility. - * In this case, this parameter will be update with the new format. - *@return Send back the absolute path of the given filename or "Neutral" if "Neutral" has been set to profName. Implementor will have - * to test for this particular value. If the absolute path is invalid (e.g. the file doesn't exist), it will return an empty string. - */ -Glib::ustring Options::findProfilePath(Glib::ustring &profName) { - if (profName.empty()) - return ""; - - if (profName == DEFPROFILE_INTERNAL) - return profName; - - Glib::ustring p = profName.substr(0, 4); - if (p=="${U}") { - // the path starts by the User virtual path - p = getUserProfilePath(); - Glib::ustring fullPath = Glib::build_filename(p, profName.substr(5) + paramFileExtension); - if (!p.empty() && safe_file_test (fullPath, Glib::FILE_TEST_EXISTS)) - return Glib::path_get_dirname(fullPath); - } - else if (p=="${G}") { - // the path starts by the User virtual path - p = getGlobalProfilePath(); - Glib::ustring fullPath = Glib::build_filename(p, profName.substr(5) + paramFileExtension); - if (!p.empty() && safe_file_test (fullPath, Glib::FILE_TEST_EXISTS)) - return Glib::path_get_dirname(fullPath); - } - else { - // compatibility case -> convert the path to the new format - p = getUserProfilePath(); - Glib::ustring fullPath = Glib::build_filename(p, profName + paramFileExtension); - if (!p.empty() && safe_file_test (fullPath, Glib::FILE_TEST_EXISTS)) { - // update the profile path - profName = Glib::build_filename("${U}", profName); - return Glib::path_get_dirname(fullPath); - } - - p = getGlobalProfilePath(); - fullPath = Glib::build_filename(p, profName + paramFileExtension); - if (!p.empty() && safe_file_test (fullPath, Glib::FILE_TEST_EXISTS)) { - profName = Glib::build_filename("${G}", profName); - return Glib::path_get_dirname(fullPath); - } - } - return ""; - -} - -void Options::setDefaults () { - - font = "sans, 8"; - windowWidth = 1200; - windowHeight = 680; - windowX = 0; - windowY = 0; - windowMaximized = true; - saveAsDialogWidth = 920; - saveAsDialogHeight = 680; - savesParamsAtExit = true; - saveFormat.format = "jpg"; - saveFormat.jpegQuality = 92; - saveFormat.jpegSubSamp = 2; - saveFormat.pngCompression = 6; - saveFormat.pngBits = 8; - saveFormat.tiffBits = 16; - saveFormat.tiffUncompressed = true; - saveFormat.saveParams = true; - - saveFormatBatch.format = "jpg"; - saveFormatBatch.jpegQuality = 92; - saveFormatBatch.jpegSubSamp = 2; - saveFormatBatch.pngCompression = 6; - saveFormatBatch.pngBits = 8; - saveFormatBatch.tiffBits = 16; - saveFormatBatch.tiffUncompressed = true; - saveFormatBatch.saveParams = true; - - savePathTemplate = "%p1/converted/%f"; - savePathFolder = ""; - saveUsePathTemplate = true; - defProfRaw = DEFPROFILE_RAW; - defProfImg = DEFPROFILE_IMG; - dateFormat = "%y-%m-%d"; - adjusterDelay = 0; - startupDir = STARTUPDIR_LAST; - startupPath = ""; - useBundledProfiles = true; - detailWindowWidth = -1; - detailWindowHeight = -1; - dirBrowserWidth = 260; - dirBrowserHeight = 350; - dirBrowserSortType = Gtk::SORT_ASCENDING; - preferencesWidth = 800; - preferencesHeight = 0; - toolPanelWidth = 400; - browserToolPanelWidth = 465; - browserToolPanelHeight = 600; - browserToolPanelOpened = true;; - browserDirPanelOpened = true; - editorFilmStripOpened = true; - historyPanelWidth = 330; - lastScale = 5; - panAccelFactor = 5; - rememberZoomAndPan = true; - lastCropSize = 1; - fbOnlyRaw = false; - fbShowDateTime = true; - fbShowBasicExif = true; - fbShowExpComp = false; - fbShowHidden = false; - fbArrangement = 2; // was 0 - multiUser = true; - profilePath = "profiles"; - loadSaveProfilePath = ""; // will be corrected in load as otherwise construction fails - version = "0.0.0.0"; // temporary value; will be correctly set in RTWindow::on_realize - thumbSize = 240; - thumbSizeTab = 180; - thumbSizeQueue = 160; - sameThumbSize = true; // preferring speed of switch between file browser and single editor tab - showHistory = true; - showFilePanelState = 0; // Not used anymore ; was the thumb strip state - showInfo = true; - cropPPI = 600; - showClippedHighlights = false; - showClippedShadows = false; - highlightThreshold = 253; // was 254 - shadowThreshold = 8; // was 0 - bgcolor = 0; - blinkClipped = false; - language = DefaultLanguage; - languageAutoDetect= langMgr.isOSLanguageDetectSupported(); - lastSaveAsPath = ""; - overwriteOutputFile = false; // if TRUE, existing output JPGs/PNGs are overwritten, instead of adding ..-1.jpg, -2.jpg etc. - theme = "25-Gray-Gray"; - slimUI = false; - useSystemTheme = false; - maxThumbnailHeight = 250; - maxCacheEntries = 20000; - thumbInterp = 1; - autoSuffix = true; - forceFormatOpts = true; - saveMethodNum = 0; // 0->immediate, 1->putToQueuHead, 2->putToQueueTail - saveParamsFile = true; // was false, but saving the procparams files next to the file make more sense when reorganizing file tree than in a cache - saveParamsCache = false; // there's no need to save the procparams files in a cache if saveParamsFile is true - paramsLoadLocation = PLL_Input; // was PLL_Cache - procQueueEnabled = false; - gimpDir = ""; - psDir = ""; - customEditorProg = ""; - editorToSendTo = 1; - liveThumbnails = true; - favoriteDirs.clear(); - tpOpen.clear (); - //crvOpen.clear (); - parseExtensions.clear (); - parseExtensionsEnabled.clear (); - parsedExtensions.clear (); - renameUseTemplates = false; - renameTemplates.clear (); - thumbnailZoomRatios.clear (); - thumbnailZoomRatios.push_back (0.2); - thumbnailZoomRatios.push_back (0.3); - thumbnailZoomRatios.push_back (0.45); - thumbnailZoomRatios.push_back (0.6); - thumbnailZoomRatios.push_back (0.8); - thumbnailZoomRatios.push_back (1.0); - overlayedFileNames = false; - filmStripOverlayedFileNames = false; - internalThumbIfUntouched = true; // if TRUE, only fast, internal preview images are taken if the image is not edited yet - showFileNames = true; - filmStripShowFileNames = false; - tabbedUI = false; - mainNBVertical = true; - multiDisplayMode = 0; - tunnelMetaData = true; - histogramPosition = 1; - histogramBar = true; - histogramFullMode = false; - curvebboxpos = 1; - prevdemo = PD_Sidecar; - rgbDenoiseThreadLimit = 0; -#if defined( _OPENMP ) && defined( __x86_64__ ) - clutCacheSize = omp_get_num_procs(); -#else - clutCacheSize = 1; -#endif - filledProfile = false; - maxInspectorBuffers = 2; // a rather conservative value for low specced systems... - serializeTiffRead = true; - - FileBrowserToolbarSingleRow = false; - hideTPVScrollbar = false; - UseIconNoText = true; - whiteBalanceSpotSize = 8; - showFilmStripToolBar = false; - menuGroupRank = true; - menuGroupLabel = true; - menuGroupFileOperations = true; - menuGroupProfileOperations = true; - menuGroupExtProg = true; - - fastexport_bypass_sharpening = true; - fastexport_bypass_sharpenEdge = true; - fastexport_bypass_sharpenMicro = true; - //fastexport_bypass_lumaDenoise = true; - //fastexport_bypass_colorDenoise = true; - fastexport_bypass_defringe = true; - fastexport_bypass_dirpyrDenoise = true; - fastexport_bypass_sh_hq = true; - fastexport_bypass_dirpyrequalizer = true; - fastexport_bypass_wavelet = true; - fastexport_raw_bayer_method = "fast"; - //fastexport_bypass_raw_bayer_all_enhance = true; - fastexport_bypass_raw_bayer_dcb_iterations = true; - fastexport_bypass_raw_bayer_dcb_enhance = true; - fastexport_bypass_raw_bayer_lmmse_iterations = true; - fastexport_bypass_raw_bayer_linenoise = true; - fastexport_bypass_raw_bayer_greenthresh = true; - fastexport_raw_xtrans_method = "fast"; - fastexport_bypass_raw_ccSteps = true; - fastexport_bypass_raw_ca = true; - fastexport_bypass_raw_df = true; - fastexport_bypass_raw_ff = true; - fastexport_icm_input = "(camera)"; - fastexport_icm_working = "ProPhoto"; - fastexport_icm_output = "RT_sRGB"; - fastexport_icm_gamma = "default"; - fastexport_resize_enabled = true; - fastexport_resize_scale = 1; - fastexport_resize_appliesTo = "Cropped area"; - fastexport_resize_method = "Lanczos"; - fastexport_resize_dataspec = 3; - fastexport_resize_width = 900; - fastexport_resize_height = 900; - - clutsDir = "./cluts"; - - cutOverlayBrush = std::vector (4); - cutOverlayBrush[3] = 0.667; // :-p - - navGuideBrush = std::vector (4); - //default to red - navGuideBrush[0] = 1.0; - navGuideBrush[1] = 0.0; - navGuideBrush[2] = 0.0; - navGuideBrush[3] = 1.0; - - sndEnable=true; - sndLngEditProcDoneSecs=3.0; -#ifdef __linux__ - sndBatchQueueDone = "complete"; - sndLngEditProcDone = "window-attention"; -#endif - - // Reminder: 0 = SET mode, 1 = ADD mode - int babehav[] = { - 0, // ADDSET_TC_EXPCOMP - 0, // ADDSET_TC_BRIGHTNESS - 0, // ADDSET_TC_BLACKLEVEL - 0, // ADDSET_TC_CONTRAST - 0, // ADDSET_SH_HIGHLIGHTS - 0, // ADDSET_SH_SHADOWS - 0, // ADDSET_SH_LOCALCONTRAST - 0, // ADDSET_LC_BRIGHTNESS - 0, // ADDSET_LC_CONTRAST - 0, // ADDSET_SHARP_AMOUNT - 0, // ADDSET_WB_TEMPERATURE - 0, // ADDSET_WB_GREEN - 0, // ADDSET_ROTATE_DEGREE - 0, // ADDSET_DIST_AMOUNT - 0, // ADDSET_PERSPECTIVE - 0, // ADDSET_CA - 0, // ADDSET_VIGN_AMOUNT - 0, // ADDSET_VIGN_RADIUS - 0, // ADDSET_VIGN_STRENGTH - 0, // ADDSET_VIGN_CENTER - 0, // ADDSET_LC_CHROMATICITY - 0, // ADDSET_TC_SATURATION - 0, // ADDSET_TC_HLCOMPAMOUNT - 0, // ADDSET_TC_HLCOMPTHRESH - 0, // ADDSET_TC_SHCOMP - 0, // ADDSET_DIRPYREQ - 0, // ADDSET_DIRPYRDN_LUMA - 0, // ADDSET_DIRPYRDN_LUDET - 0, // ADDSET_DIRPYRDN_CHROMA - 0, // ADDSET_DIRPYRDN_CHROMARED - 0, // ADDSET_DIRPYRDN_CHROMABLUE - 0, // ADDSET_DIRPYRDN_GAMMA - 0, // ADDSET_CHMIXER - 0, // ADDSET_PREPROCESS_GREENEQUIL - 0, // ADDSET_PREPROCESS_LINEDENOISE - 0, // ADDSET_RAWCACORR - 0, // ADDSET_RAWEXPOS_LINEAR - 0, // ADDSET_RAWEXPOS_PRESER - 0, // ADDSET_RAWEXPOS_BLACKS - 0, // ADDSET_SHARPENEDGE_AMOUNT - 0, // ADDSET_SHARPENMICRO_AMOUNT - 0, // ADDSET_SHARPENEDGE_PASS - 0, // ADDSET_SHARPENMICRO_UNIFORMITY - 0, // ADDSET_VIBRANCE_PASTELS - 0, // ADDSET_VIBRANCE_SATURATED - 0, // ADDSET_FREE_OUPUT_GAMMA - 0, // ADDSET_FREE_OUTPUT_SLOPE - 0, // ADDSET_CAT_DEGREE - 0, // ADDSET_CAT_ADAPSCEN - 0, // ADDSET_CAT_ADAPLUM - 0, // ADDSET_CAT_LIGHT - 0, // ADDSET_CAT_RSTPRO - 0, // ADDSET_CAT_BADPIX - 0, // ADDSET_CAT_JLIGHT - 0, // ADDSET_CAT_CHROMA - 0, // ADDSET_CAT_CONTRAST - 0, // ADDSET_CAT_CHROMA_S - 0, // ADDSET_CAT_CHROMA_M - 0, // ADDSET_CAT_HUE - 0, // ADDSET_CAT_BADPIX - 0, // ADDSET_WB_EQUAL - 0, // ADDSET_GRADIENT_DEGREE - 0, // ADDSET_GRADIENT_FEATHER - 0, // ADDSET_GRADIENT_STRENGTH - 0, // ADDSET_GRADIENT_CENTER - 0, // ADDSET_PCVIGNETTE_STRENGTH - 0, // ADDSET_PCVIGNETTE_FEATHER - 0, // ADDSET_PCVIGNETTE_ROUNDNESS - 0, // ADDSET_BLACKWHITE_HUES - 0, // ADDSET_BLACKWHITE_GAMMA - 0, // ADDSET_DIRPYREQ_THRESHOLD - 0, // ADDSET_DIRPYREQ_SKINPROTECT - 0, // ADDSET_COLORTONING_SPLIT - 0, //ADDSET_DIRPYRDN_PASSES - 0, // ADDSET_RAWFFCLIPCONTROL - 0, // ADDSET_FILMSIMULATION_STRENGTH - 0, //ADDSET_WA - 0, //ADDSET_WA_THRESHOLD - 0, //ADDSET_WA_THRESHOLD2 - 0, //ADDSET_WA_THRES - 0, //ADDSET_WA_CHRO - 0, //ADDSET_WA_CHROMA - 0, //ADDSET_WA_CONTRAST - 0, //ADDSET_WA_SKINPROTECT - 0, //ADDSET_WA_RESCHRO - 0, //ADDSET_WA_RESCON - 0, //ADDSET_WA_RESCONH - 0, //ADDSET_WA_THRR - 0, //ADDSET_WA_THRRH - 0, //ADDSET_WA_SKYPROTECT - 0, //ADDSET_WA_EDGRAD - 0, //ADDSET_WA_EDGVAL - 0, //ADDSET_WA_STRENGTH - 0, //ADDSET_WA_EDGEDETECT - 0, //ADDSET_WA_EDGEDETECTTHR - 0, //ADDSET_WA_EDGEDETECTTHR2 - 0, //ADDSET_WA_TMRS - 0, //ADDSET_WA_GAMMA - - }; - baBehav = std::vector (babehav, babehav+ADDSET_PARAM_NUM); - - rtSettings.darkFramesPath = ""; - rtSettings.flatFieldsPath = ""; -#ifdef WIN32 - const gchar* sysRoot = g_getenv("SystemRoot"); // Returns e.g. "c:\Windows" - if (sysRoot!=NULL) - rtSettings.iccDirectory = Glib::ustring(sysRoot) + Glib::ustring("\\System32\\spool\\drivers\\color"); - else - rtSettings.iccDirectory = "C:\\WINDOWS\\System32\\spool\\drivers\\color"; -#elif defined __APPLE__ - rtSettings.iccDirectory = "/library/ColorSync/Profiles/Displays"; -#else - rtSettings.iccDirectory = "/usr/share/color/icc"; -#endif - rtSettings.colorimetricIntent = 1; - rtSettings.viewingdevice=0; - rtSettings.viewingdevicegrey=3; - rtSettings.viewinggreySc=1; - rtSettings.leveldnv=2; - rtSettings.leveldnti=0; - rtSettings.leveldnaut=0; - rtSettings.leveldnliss=0; - rtSettings.leveldnautsimpl=0; - - rtSettings.monitorProfile = ""; - rtSettings.autoMonitorProfile = false; - rtSettings.adobe = "RT_Medium_gsRGB"; // put the name of yours profiles (here windows) - rtSettings.prophoto = "RT_Large_gBT709"; // these names appear in the menu "output profile" - rtSettings.prophoto10 = "RT_Large_g10"; // these names appear in the menu "output profile" - rtSettings.srgb10 = "RT_sRGB_g10"; - rtSettings.widegamut = "WideGamutRGB"; - rtSettings.srgb = "RT_sRGB"; - rtSettings.bruce = "Bruce"; - rtSettings.beta = "BetaRGB"; - rtSettings.best = "BestRGB"; - rtSettings.verbose = false; - rtSettings.gamutICC = true; - rtSettings.gamutLch = true; - rtSettings.amchroma = 40;//between 20 and 140 low values increase effect..and also artefacts, high values reduces - rtSettings.artifact_cbdl = 4.; - rtSettings.level0_cbdl = 0; - rtSettings.level123_cbdl = 30; - rtSettings.bot_left=0; - rtSettings.top_left=10; - rtSettings.top_right=40; - rtSettings.bot_right=75; - rtSettings.ed_detec=3;//between 2 and 10 - rtSettings.ed_detecStr=1.3;//not use - rtSettings.ed_low=15.;//between 5 to 40 - rtSettings.ed_lipinfl=0.8;//between 0.5 to 0.9 - rtSettings.ed_lipampl=1.1;//between 1 and 2 - - - rtSettings.ciecamfloat = true; - rtSettings.protectred = 60; - rtSettings.protectredh = 0.3; - rtSettings.CRI_color =0; - rtSettings.autocielab=true; - rtSettings.denoiselabgamma=2; - rtSettings.HistogramWorking = false; - - rtSettings.daubech = false; - - rtSettings.nrauto = 10;//between 2 and 20 - rtSettings.nrautomax = 40;//between 5 and 100 - rtSettings.nrhigh = 0.45;//between 0.1 and 0.9 - rtSettings.nrwavlevel = 1;//integer between 0 and 2 - - // rtSettings.colortoningab =0.7; -//rtSettings.decaction =0.3; -// rtSettings.ciebadpixgauss=false; - rtSettings.rgbcurveslumamode_gamut=true; - lastIccDir = rtSettings.iccDirectory; - lastDarkframeDir = rtSettings.darkFramesPath; - lastFlatfieldDir = rtSettings.flatFieldsPath; -// rtSettings.bw_complementary = true; - // There is no reasonable default for curves. We can still suppose that they will take place - // in a subdirectory of the user's own ProcParams presets, i.e. in a subdirectory - // of the one pointed to by the "profile" field. - // The following fields will then be initialized when "profile" will have its final value, - // at the end of the "updatePaths" method. - lastRgbCurvesDir = ""; - lastLabCurvesDir = ""; - lastDenoiseCurvesDir = ""; - lastWaveletCurvesDir = ""; - lastPFCurvesDir = ""; - lastHsvCurvesDir = ""; - lastToneCurvesDir = ""; - lastVibranceCurvesDir = ""; - lastProfilingReferenceDir = ""; - lastBWCurvesDir = ""; - maxRecentFolders = 15; -} - -Options* Options::copyFrom (Options* other) { - *this = *other; - return this; -} - -void Options::filterOutParsedExtensions () { - parsedExtensions.clear(); - for (unsigned int i=0; i + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "options.h" +#include +#include +#include +#include "multilangmgr.h" +#include "../rtengine/safekeyfile.h" +#include "addsetids.h" +#include "guiutils.h" +#include "../rtengine/safegtk.h" +#include "version.h" + +#ifdef _OPENMP +#include +#endif + + + +#ifdef WIN32 +#include +// for GCC32 +#ifndef _WIN32_IE +#define _WIN32_IE 0x0600 +#endif +#include +#endif + +// User's settings directory, including images' profiles if used +Glib::ustring Options::rtdir; +// User's cached datas' directory +Glib::ustring Options::cacheBaseDir; + +Options options; +Glib::ustring versionString = VERSION; +Glib::ustring versionSuffixString = VERSION_SUFFIX; +Glib::ustring paramFileExtension = ".pp3"; + +Options::Options () { + + defProfRawMissing = false; + defProfImgMissing = false; + setDefaults (); +} + +const char *DefaultLanguage = "English (US)"; + +inline bool Options::checkProfilePath(Glib::ustring &path) { + if (path.empty()) + return false; + + Glib::ustring p = getUserProfilePath(); + if (!p.empty() && safe_file_test (path+paramFileExtension, Glib::FILE_TEST_EXISTS)) + return true; + + p = getGlobalProfilePath(); + if (!p.empty() && safe_file_test (path+paramFileExtension, Glib::FILE_TEST_EXISTS)) + return true; + else + return false; +} + +bool Options::checkDirPath(Glib::ustring &path, Glib::ustring errString) { + if (safe_file_test (path, Glib::FILE_TEST_EXISTS) && safe_file_test (path, Glib::FILE_TEST_IS_DIR)) + return true; + else { + if (!errString.empty()) printf("%s\n", errString.c_str()); + return false; + } +} + +void Options::updatePaths() { + + Glib::ustring tmpPath; + + userProfilePath = ""; + globalProfilePath = ""; + + if (Glib::path_is_absolute(profilePath)) { + // absolute path + if (!checkDirPath (profilePath, "")) { + safe_g_mkdir_with_parents (profilePath, 511); + if (!checkDirPath (profilePath, "")) // had problems with mkdir_with_parents return value on OS X, just check dir again + printf("Error: user's profiles' directory \"%s\" creation failed\n", profilePath.c_str()); + } + if (checkDirPath (profilePath, "Error: the specified user's profiles' path doesn't point to a directory or doesn't exist!\n")) { + if (multiUser) { + userProfilePath = profilePath; + tmpPath = Glib::build_filename(argv0, "profiles"); + if(checkDirPath (tmpPath, "Error: the global's profiles' path doesn't point to a directory or doesn't exist!\n")) { + if (userProfilePath != tmpPath) + globalProfilePath = tmpPath; + } + } + else { + globalProfilePath = profilePath; + } + } + else { + tmpPath = Glib::build_filename(argv0, "profiles"); + if(checkDirPath (tmpPath, "Error: the global's profiles' path doesn't point to a directory or doesn't exist!\n")) { + globalProfilePath = tmpPath; + } + } + } + else { + // relative paths + if (multiUser) { + tmpPath = Glib::build_filename(rtdir, profilePath); + if (!checkDirPath (tmpPath, "")) { + safe_g_mkdir_with_parents (tmpPath, 511); + if (!checkDirPath (tmpPath, "")) + printf("Error: user's profiles' directory \"%s\" creation failed\n", tmpPath.c_str()); + } + if(checkDirPath (tmpPath, "Error: the specified user's profiles' path doesn't point to a directory!\n")) { + userProfilePath = tmpPath; + } + tmpPath = Glib::build_filename(argv0, "profiles"); + if(checkDirPath (tmpPath, "Error: the specified user's profiles' path doesn't point to a directory or doesn't exist!\n")) { + globalProfilePath = tmpPath; + } + } + else { + // common directory + // directory name set in options is ignored, we use the default directory name + tmpPath = Glib::build_filename(argv0, "profiles"); + if(checkDirPath (tmpPath, "Error: no global profiles' directory found!\n")) { + globalProfilePath = tmpPath; + } + } + } + + Glib::ustring preferredPath = getPreferredProfilePath(); + // Paths are updated only if the user or global profile path is set + if (lastRgbCurvesDir.empty() || !safe_file_test (lastRgbCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastRgbCurvesDir, Glib::FILE_TEST_IS_DIR)) + lastRgbCurvesDir = preferredPath; + if (lastLabCurvesDir.empty() || !safe_file_test (lastLabCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastLabCurvesDir, Glib::FILE_TEST_IS_DIR)) + lastLabCurvesDir = preferredPath; + if (lastDenoiseCurvesDir.empty() || !safe_file_test (lastDenoiseCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastDenoiseCurvesDir, Glib::FILE_TEST_IS_DIR)) + lastDenoiseCurvesDir = preferredPath; + if (lastWaveletCurvesDir.empty() || !safe_file_test (lastWaveletCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastWaveletCurvesDir, Glib::FILE_TEST_IS_DIR)) + lastWaveletCurvesDir = preferredPath; + + if (lastPFCurvesDir.empty() || !safe_file_test (lastPFCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastPFCurvesDir, Glib::FILE_TEST_IS_DIR)) + lastPFCurvesDir = preferredPath; + if (lastHsvCurvesDir.empty() || !safe_file_test (lastHsvCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastHsvCurvesDir, Glib::FILE_TEST_IS_DIR)) + lastHsvCurvesDir = preferredPath; + if (lastToneCurvesDir.empty() || !safe_file_test (lastToneCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastToneCurvesDir, Glib::FILE_TEST_IS_DIR)) + lastToneCurvesDir = preferredPath; + if (lastProfilingReferenceDir.empty() || !safe_file_test (lastProfilingReferenceDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastProfilingReferenceDir, Glib::FILE_TEST_IS_DIR)) + lastProfilingReferenceDir = preferredPath; + if (lastVibranceCurvesDir.empty() || !safe_file_test (lastVibranceCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastVibranceCurvesDir, Glib::FILE_TEST_IS_DIR)) + lastVibranceCurvesDir = preferredPath; + if (loadSaveProfilePath.empty() || !safe_file_test (loadSaveProfilePath, Glib::FILE_TEST_EXISTS) || !safe_file_test (loadSaveProfilePath, Glib::FILE_TEST_IS_DIR)) + loadSaveProfilePath = preferredPath; + if (lastBWCurvesDir.empty() || !safe_file_test (lastBWCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastBWCurvesDir, Glib::FILE_TEST_IS_DIR)) + lastBWCurvesDir = preferredPath; + +} + +Glib::ustring Options::getPreferredProfilePath() { + if (!userProfilePath.empty()) + return userProfilePath; + else if (!globalProfilePath.empty()) + return globalProfilePath; + else + return ""; +} + +/** @brief Get the absolute path of the given filename or the "Neutral" special value + * + *@param profName path + filename of the procparam to look for. A filename without path can be provided for backward compatibility. + * In this case, this parameter will be update with the new format. + *@return Send back the absolute path of the given filename or "Neutral" if "Neutral" has been set to profName. Implementor will have + * to test for this particular value. If the absolute path is invalid (e.g. the file doesn't exist), it will return an empty string. + */ +Glib::ustring Options::findProfilePath(Glib::ustring &profName) { + if (profName.empty()) + return ""; + + if (profName == DEFPROFILE_INTERNAL) + return profName; + + Glib::ustring p = profName.substr(0, 4); + if (p=="${U}") { + // the path starts by the User virtual path + p = getUserProfilePath(); + Glib::ustring fullPath = Glib::build_filename(p, profName.substr(5) + paramFileExtension); + if (!p.empty() && safe_file_test (fullPath, Glib::FILE_TEST_EXISTS)) + return Glib::path_get_dirname(fullPath); + } + else if (p=="${G}") { + // the path starts by the User virtual path + p = getGlobalProfilePath(); + Glib::ustring fullPath = Glib::build_filename(p, profName.substr(5) + paramFileExtension); + if (!p.empty() && safe_file_test (fullPath, Glib::FILE_TEST_EXISTS)) + return Glib::path_get_dirname(fullPath); + } + else { + // compatibility case -> convert the path to the new format + p = getUserProfilePath(); + Glib::ustring fullPath = Glib::build_filename(p, profName + paramFileExtension); + if (!p.empty() && safe_file_test (fullPath, Glib::FILE_TEST_EXISTS)) { + // update the profile path + profName = Glib::build_filename("${U}", profName); + return Glib::path_get_dirname(fullPath); + } + + p = getGlobalProfilePath(); + fullPath = Glib::build_filename(p, profName + paramFileExtension); + if (!p.empty() && safe_file_test (fullPath, Glib::FILE_TEST_EXISTS)) { + profName = Glib::build_filename("${G}", profName); + return Glib::path_get_dirname(fullPath); + } + } + return ""; + +} + +void Options::setDefaults () { + + font = "sans, 8"; + windowWidth = 1200; + windowHeight = 680; + windowX = 0; + windowY = 0; + windowMaximized = true; + saveAsDialogWidth = 920; + saveAsDialogHeight = 680; + savesParamsAtExit = true; + saveFormat.format = "jpg"; + saveFormat.jpegQuality = 92; + saveFormat.jpegSubSamp = 2; + saveFormat.pngCompression = 6; + saveFormat.pngBits = 8; + saveFormat.tiffBits = 16; + saveFormat.tiffUncompressed = true; + saveFormat.saveParams = true; + + saveFormatBatch.format = "jpg"; + saveFormatBatch.jpegQuality = 92; + saveFormatBatch.jpegSubSamp = 2; + saveFormatBatch.pngCompression = 6; + saveFormatBatch.pngBits = 8; + saveFormatBatch.tiffBits = 16; + saveFormatBatch.tiffUncompressed = true; + saveFormatBatch.saveParams = true; + + savePathTemplate = "%p1/converted/%f"; + savePathFolder = ""; + saveUsePathTemplate = true; + defProfRaw = DEFPROFILE_RAW; + defProfImg = DEFPROFILE_IMG; + dateFormat = "%y-%m-%d"; + adjusterDelay = 0; + startupDir = STARTUPDIR_LAST; + startupPath = ""; + useBundledProfiles = true; + detailWindowWidth = -1; + detailWindowHeight = -1; + dirBrowserWidth = 260; + dirBrowserHeight = 350; + dirBrowserSortType = Gtk::SORT_ASCENDING; + preferencesWidth = 800; + preferencesHeight = 0; + toolPanelWidth = 400; + browserToolPanelWidth = 465; + browserToolPanelHeight = 600; + browserToolPanelOpened = true;; + browserDirPanelOpened = true; + editorFilmStripOpened = true; + historyPanelWidth = 330; + lastScale = 5; + panAccelFactor = 5; + rememberZoomAndPan = true; + lastCropSize = 1; + fbOnlyRaw = false; + fbShowDateTime = true; + fbShowBasicExif = true; + fbShowExpComp = false; + fbShowHidden = false; + fbArrangement = 2; // was 0 + multiUser = true; + profilePath = "profiles"; + loadSaveProfilePath = ""; // will be corrected in load as otherwise construction fails + version = "0.0.0.0"; // temporary value; will be correctly set in RTWindow::on_realize + thumbSize = 240; + thumbSizeTab = 180; + thumbSizeQueue = 160; + sameThumbSize = true; // preferring speed of switch between file browser and single editor tab + showHistory = true; + showFilePanelState = 0; // Not used anymore ; was the thumb strip state + showInfo = true; + cropPPI = 600; + showClippedHighlights = false; + showClippedShadows = false; + highlightThreshold = 253; // was 254 + shadowThreshold = 8; // was 0 + bgcolor = 0; + blinkClipped = false; + language = DefaultLanguage; + languageAutoDetect= langMgr.isOSLanguageDetectSupported(); + lastSaveAsPath = ""; + overwriteOutputFile = false; // if TRUE, existing output JPGs/PNGs are overwritten, instead of adding ..-1.jpg, -2.jpg etc. + theme = "25-Gray-Gray"; + slimUI = false; + useSystemTheme = false; + maxThumbnailHeight = 250; + maxCacheEntries = 20000; + thumbInterp = 1; + autoSuffix = true; + forceFormatOpts = true; + saveMethodNum = 0; // 0->immediate, 1->putToQueuHead, 2->putToQueueTail + saveParamsFile = true; // was false, but saving the procparams files next to the file make more sense when reorganizing file tree than in a cache + saveParamsCache = false; // there's no need to save the procparams files in a cache if saveParamsFile is true + paramsLoadLocation = PLL_Input; // was PLL_Cache + procQueueEnabled = false; + gimpDir = ""; + psDir = ""; + customEditorProg = ""; + editorToSendTo = 1; + liveThumbnails = true; + favoriteDirs.clear(); + tpOpen.clear (); + //crvOpen.clear (); + parseExtensions.clear (); + parseExtensionsEnabled.clear (); + parsedExtensions.clear (); + renameUseTemplates = false; + renameTemplates.clear (); + thumbnailZoomRatios.clear (); + thumbnailZoomRatios.push_back (0.2); + thumbnailZoomRatios.push_back (0.3); + thumbnailZoomRatios.push_back (0.45); + thumbnailZoomRatios.push_back (0.6); + thumbnailZoomRatios.push_back (0.8); + thumbnailZoomRatios.push_back (1.0); + overlayedFileNames = false; + filmStripOverlayedFileNames = false; + internalThumbIfUntouched = true; // if TRUE, only fast, internal preview images are taken if the image is not edited yet + showFileNames = true; + filmStripShowFileNames = false; + tabbedUI = false; + mainNBVertical = true; + multiDisplayMode = 0; + tunnelMetaData = true; + histogramPosition = 1; + histogramBar = true; + histogramFullMode = false; + curvebboxpos = 1; + prevdemo = PD_Sidecar; + rgbDenoiseThreadLimit = 0; +#if defined( _OPENMP ) && defined( __x86_64__ ) + clutCacheSize = omp_get_num_procs(); +#else + clutCacheSize = 1; +#endif + filledProfile = false; + maxInspectorBuffers = 2; // a rather conservative value for low specced systems... + serializeTiffRead = true; + + FileBrowserToolbarSingleRow = false; + hideTPVScrollbar = false; + UseIconNoText = true; + whiteBalanceSpotSize = 8; + showFilmStripToolBar = false; + menuGroupRank = true; + menuGroupLabel = true; + menuGroupFileOperations = true; + menuGroupProfileOperations = true; + menuGroupExtProg = true; + + fastexport_bypass_sharpening = true; + fastexport_bypass_sharpenEdge = true; + fastexport_bypass_sharpenMicro = true; + //fastexport_bypass_lumaDenoise = true; + //fastexport_bypass_colorDenoise = true; + fastexport_bypass_defringe = true; + fastexport_bypass_dirpyrDenoise = true; + fastexport_bypass_sh_hq = true; + fastexport_bypass_dirpyrequalizer = true; + fastexport_bypass_wavelet = true; + fastexport_raw_bayer_method = "fast"; + //fastexport_bypass_raw_bayer_all_enhance = true; + fastexport_bypass_raw_bayer_dcb_iterations = true; + fastexport_bypass_raw_bayer_dcb_enhance = true; + fastexport_bypass_raw_bayer_lmmse_iterations = true; + fastexport_bypass_raw_bayer_linenoise = true; + fastexport_bypass_raw_bayer_greenthresh = true; + fastexport_raw_xtrans_method = "fast"; + fastexport_bypass_raw_ccSteps = true; + fastexport_bypass_raw_ca = true; + fastexport_bypass_raw_df = true; + fastexport_bypass_raw_ff = true; + fastexport_icm_input = "(camera)"; + fastexport_icm_working = "ProPhoto"; + fastexport_icm_output = "RT_sRGB"; + fastexport_icm_gamma = "default"; + fastexport_resize_enabled = true; + fastexport_resize_scale = 1; + fastexport_resize_appliesTo = "Cropped area"; + fastexport_resize_method = "Lanczos"; + fastexport_resize_dataspec = 3; + fastexport_resize_width = 900; + fastexport_resize_height = 900; + + clutsDir = "./cluts"; + + cutOverlayBrush = std::vector (4); + cutOverlayBrush[3] = 0.667; // :-p + + navGuideBrush = std::vector (4); + //default to red + navGuideBrush[0] = 1.0; + navGuideBrush[1] = 0.0; + navGuideBrush[2] = 0.0; + navGuideBrush[3] = 1.0; + + sndEnable=true; + sndLngEditProcDoneSecs=3.0; +#ifdef __linux__ + sndBatchQueueDone = "complete"; + sndLngEditProcDone = "window-attention"; +#endif + + // Reminder: 0 = SET mode, 1 = ADD mode + int babehav[] = { + 0, // ADDSET_TC_EXPCOMP + 0, // ADDSET_TC_BRIGHTNESS + 0, // ADDSET_TC_BLACKLEVEL + 0, // ADDSET_TC_CONTRAST + 0, // ADDSET_SH_HIGHLIGHTS + 0, // ADDSET_SH_SHADOWS + 0, // ADDSET_SH_LOCALCONTRAST + 0, // ADDSET_LC_BRIGHTNESS + 0, // ADDSET_LC_CONTRAST + 0, // ADDSET_SHARP_AMOUNT + 0, // ADDSET_WB_TEMPERATURE + 0, // ADDSET_WB_GREEN + 0, // ADDSET_ROTATE_DEGREE + 0, // ADDSET_DIST_AMOUNT + 0, // ADDSET_PERSPECTIVE + 0, // ADDSET_CA + 0, // ADDSET_VIGN_AMOUNT + 0, // ADDSET_VIGN_RADIUS + 0, // ADDSET_VIGN_STRENGTH + 0, // ADDSET_VIGN_CENTER + 0, // ADDSET_LC_CHROMATICITY + 0, // ADDSET_TC_SATURATION + 0, // ADDSET_TC_HLCOMPAMOUNT + 0, // ADDSET_TC_HLCOMPTHRESH + 0, // ADDSET_TC_SHCOMP + 0, // ADDSET_DIRPYREQ + 0, // ADDSET_DIRPYRDN_LUMA + 0, // ADDSET_DIRPYRDN_LUDET + 0, // ADDSET_DIRPYRDN_CHROMA + 0, // ADDSET_DIRPYRDN_CHROMARED + 0, // ADDSET_DIRPYRDN_CHROMABLUE + 0, // ADDSET_DIRPYRDN_GAMMA + 0, // ADDSET_CHMIXER + 0, // ADDSET_PREPROCESS_GREENEQUIL + 0, // ADDSET_PREPROCESS_LINEDENOISE + 0, // ADDSET_RAWCACORR + 0, // ADDSET_RAWEXPOS_LINEAR + 0, // ADDSET_RAWEXPOS_PRESER + 0, // ADDSET_RAWEXPOS_BLACKS + 0, // ADDSET_SHARPENEDGE_AMOUNT + 0, // ADDSET_SHARPENMICRO_AMOUNT + 0, // ADDSET_SHARPENEDGE_PASS + 0, // ADDSET_SHARPENMICRO_UNIFORMITY + 0, // ADDSET_VIBRANCE_PASTELS + 0, // ADDSET_VIBRANCE_SATURATED + 0, // ADDSET_FREE_OUPUT_GAMMA + 0, // ADDSET_FREE_OUTPUT_SLOPE + 0, // ADDSET_CAT_DEGREE + 0, // ADDSET_CAT_ADAPSCEN + 0, // ADDSET_CAT_ADAPLUM + 0, // ADDSET_CAT_LIGHT + 0, // ADDSET_CAT_RSTPRO + 0, // ADDSET_CAT_BADPIX + 0, // ADDSET_CAT_JLIGHT + 0, // ADDSET_CAT_CHROMA + 0, // ADDSET_CAT_CONTRAST + 0, // ADDSET_CAT_CHROMA_S + 0, // ADDSET_CAT_CHROMA_M + 0, // ADDSET_CAT_HUE + 0, // ADDSET_CAT_BADPIX + 0, // ADDSET_WB_EQUAL + 0, // ADDSET_GRADIENT_DEGREE + 0, // ADDSET_GRADIENT_FEATHER + 0, // ADDSET_GRADIENT_STRENGTH + 0, // ADDSET_GRADIENT_CENTER + 0, // ADDSET_PCVIGNETTE_STRENGTH + 0, // ADDSET_PCVIGNETTE_FEATHER + 0, // ADDSET_PCVIGNETTE_ROUNDNESS + 0, // ADDSET_BLACKWHITE_HUES + 0, // ADDSET_BLACKWHITE_GAMMA + 0, // ADDSET_DIRPYREQ_THRESHOLD + 0, // ADDSET_DIRPYREQ_SKINPROTECT + 0, // ADDSET_COLORTONING_SPLIT + 0, //ADDSET_DIRPYRDN_PASSES + 0, // ADDSET_RAWFFCLIPCONTROL + 0, // ADDSET_FILMSIMULATION_STRENGTH + 0, //ADDSET_WA + 0, //ADDSET_WA_THRESHOLD + 0, //ADDSET_WA_THRESHOLD2 + 0, //ADDSET_WA_THRES + 0, //ADDSET_WA_CHRO + 0, //ADDSET_WA_CHROMA + 0, //ADDSET_WA_CONTRAST + 0, //ADDSET_WA_SKINPROTECT + 0, //ADDSET_WA_RESCHRO + 0, //ADDSET_WA_RESCON + 0, //ADDSET_WA_RESCONH + 0, //ADDSET_WA_THRR + 0, //ADDSET_WA_THRRH + 0, //ADDSET_WA_SKYPROTECT + 0, //ADDSET_WA_EDGRAD + 0, //ADDSET_WA_EDGVAL + 0, //ADDSET_WA_STRENGTH + 0, //ADDSET_WA_EDGEDETECT + 0, //ADDSET_WA_EDGEDETECTTHR + 0, //ADDSET_WA_EDGEDETECTTHR2 + 0, //ADDSET_WA_TMRS + 0, //ADDSET_WA_GAMMA + + }; + baBehav = std::vector (babehav, babehav+ADDSET_PARAM_NUM); + + rtSettings.darkFramesPath = ""; + rtSettings.flatFieldsPath = ""; +#ifdef WIN32 + const gchar* sysRoot = g_getenv("SystemRoot"); // Returns e.g. "c:\Windows" + if (sysRoot!=NULL) + rtSettings.iccDirectory = Glib::ustring(sysRoot) + Glib::ustring("\\System32\\spool\\drivers\\color"); + else + rtSettings.iccDirectory = "C:\\WINDOWS\\System32\\spool\\drivers\\color"; +#elif defined __APPLE__ + rtSettings.iccDirectory = "/library/ColorSync/Profiles/Displays"; +#else + rtSettings.iccDirectory = "/usr/share/color/icc"; +#endif + rtSettings.colorimetricIntent = 1; + rtSettings.viewingdevice=0; + rtSettings.viewingdevicegrey=3; + rtSettings.viewinggreySc=1; + rtSettings.leveldnv=2; + rtSettings.leveldnti=0; + rtSettings.leveldnaut=0; + rtSettings.leveldnliss=0; + rtSettings.leveldnautsimpl=0; + + rtSettings.monitorProfile = ""; + rtSettings.autoMonitorProfile = false; + rtSettings.adobe = "RT_Medium_gsRGB"; // put the name of yours profiles (here windows) + rtSettings.prophoto = "RT_Large_gBT709"; // these names appear in the menu "output profile" + rtSettings.prophoto10 = "RT_Large_g10"; // these names appear in the menu "output profile" + rtSettings.srgb10 = "RT_sRGB_g10"; + rtSettings.widegamut = "WideGamutRGB"; + rtSettings.srgb = "RT_sRGB"; + rtSettings.bruce = "Bruce"; + rtSettings.beta = "BetaRGB"; + rtSettings.best = "BestRGB"; + rtSettings.verbose = false; + rtSettings.gamutICC = true; + rtSettings.gamutLch = true; + rtSettings.amchroma = 40;//between 20 and 140 low values increase effect..and also artefacts, high values reduces + rtSettings.artifact_cbdl = 4.; + rtSettings.level0_cbdl = 0; + rtSettings.level123_cbdl = 30; + rtSettings.bot_left=0; + rtSettings.top_left=10; + rtSettings.top_right=40; + rtSettings.bot_right=75; + rtSettings.ed_detec=3;//between 2 and 10 + rtSettings.ed_detecStr=1.3;//not use + rtSettings.ed_low=15.;//between 5 to 40 + rtSettings.ed_lipinfl=0.8;//between 0.5 to 0.9 + rtSettings.ed_lipampl=1.1;//between 1 and 2 + + + rtSettings.ciecamfloat = true; + rtSettings.protectred = 60; + rtSettings.protectredh = 0.3; + rtSettings.CRI_color =0; + rtSettings.autocielab=true; + rtSettings.denoiselabgamma=2; + rtSettings.HistogramWorking = false; + + rtSettings.daubech = false; + + rtSettings.nrauto = 10;//between 2 and 20 + rtSettings.nrautomax = 40;//between 5 and 100 + rtSettings.nrhigh = 0.45;//between 0.1 and 0.9 + rtSettings.nrwavlevel = 1;//integer between 0 and 2 + + // rtSettings.colortoningab =0.7; +//rtSettings.decaction =0.3; +// rtSettings.ciebadpixgauss=false; + rtSettings.rgbcurveslumamode_gamut=true; + lastIccDir = rtSettings.iccDirectory; + lastDarkframeDir = rtSettings.darkFramesPath; + lastFlatfieldDir = rtSettings.flatFieldsPath; +// rtSettings.bw_complementary = true; + // There is no reasonable default for curves. We can still suppose that they will take place + // in a subdirectory of the user's own ProcParams presets, i.e. in a subdirectory + // of the one pointed to by the "profile" field. + // The following fields will then be initialized when "profile" will have its final value, + // at the end of the "updatePaths" method. + lastRgbCurvesDir = ""; + lastLabCurvesDir = ""; + lastDenoiseCurvesDir = ""; + lastWaveletCurvesDir = ""; + lastPFCurvesDir = ""; + lastHsvCurvesDir = ""; + lastToneCurvesDir = ""; + lastVibranceCurvesDir = ""; + lastProfilingReferenceDir = ""; + lastBWCurvesDir = ""; + maxRecentFolders = 15; +} + +Options* Options::copyFrom (Options* other) { + *this = *other; + return this; +} + +void Options::filterOutParsedExtensions () { + parsedExtensions.clear(); + for (unsigned int i=0; i(keyFile.get_integer ("GUI", "SortType")); - if (keyFile.has_key ("GUI", "PreferencesWidth")) preferencesWidth = keyFile.get_integer ("GUI", "PreferencesWidth"); - if (keyFile.has_key ("GUI", "PreferencesHeight")) preferencesHeight = keyFile.get_integer ("GUI", "PreferencesHeight"); - if (keyFile.has_key ("GUI", "SaveAsDialogWidth")) saveAsDialogWidth = keyFile.get_integer ("GUI", "SaveAsDialogWidth"); - if (keyFile.has_key ("GUI", "SaveAsDialogHeight")) saveAsDialogHeight = keyFile.get_integer ("GUI", "SaveAsDialogHeight"); - if (keyFile.has_key ("GUI", "ToolPanelWidth")) toolPanelWidth = keyFile.get_integer ("GUI", "ToolPanelWidth"); - if (keyFile.has_key ("GUI", "BrowserToolPanelWidth")) browserToolPanelWidth = keyFile.get_integer ("GUI", "BrowserToolPanelWidth"); - if (keyFile.has_key ("GUI", "BrowserToolPanelHeight")) browserToolPanelHeight = keyFile.get_integer ("GUI", "BrowserToolPanelHeight"); - if (keyFile.has_key ("GUI", "BrowserToolPanelOpened")) browserToolPanelOpened = keyFile.get_boolean ("GUI", "BrowserToolPanelOpened"); - if (keyFile.has_key ("GUI", "BrowserDirPanelOpened")) browserDirPanelOpened = keyFile.get_boolean ("GUI", "BrowserDirPanelOpened"); - if (keyFile.has_key ("GUI", "EditorFilmStripOpened")) editorFilmStripOpened = keyFile.get_boolean ("GUI", "EditorFilmStripOpened"); - if (keyFile.has_key ("GUI", "HistoryPanelWidth")) historyPanelWidth = keyFile.get_integer ("GUI", "HistoryPanelWidth"); - if (keyFile.has_key ("GUI", "LastPreviewScale")) lastScale = keyFile.get_integer ("GUI", "LastPreviewScale"); - if (keyFile.has_key ("GUI", "PanAccelFactor")) panAccelFactor = keyFile.get_integer ("GUI", "PanAccelFactor"); - if (keyFile.has_key ("GUI", "RememberZoomAndPan")) rememberZoomAndPan = keyFile.get_boolean ("GUI", "RememberZoomAndPan"); - if (keyFile.has_key ("GUI", "LastCropSize")) lastCropSize = keyFile.get_integer ("GUI", "LastCropSize"); - if (keyFile.has_key ("GUI", "ShowHistory")) showHistory = keyFile.get_boolean ("GUI", "ShowHistory"); - if (keyFile.has_key ("GUI", "ShowFilePanelState")) showFilePanelState= keyFile.get_integer ("GUI", "ShowFilePanelState"); - if (keyFile.has_key ("GUI", "ShowInfo")) showInfo = keyFile.get_boolean ("GUI", "ShowInfo"); - if (keyFile.has_key ("GUI", "MainNBVertical")) mainNBVertical = keyFile.get_boolean ("GUI", "MainNBVertical"); - if (keyFile.has_key ("GUI", "ShowClippedHighlights"))showClippedHighlights = keyFile.get_boolean ("GUI", "ShowClippedHighlights"); - if (keyFile.has_key ("GUI", "ShowClippedShadows")) showClippedShadows= keyFile.get_boolean ("GUI", "ShowClippedShadows"); - if (keyFile.has_key ("GUI", "FrameColor")) bgcolor = keyFile.get_integer ("GUI", "FrameColor"); - if (keyFile.has_key ("GUI", "ProcessingQueueEnbled"))procQueueEnabled = keyFile.get_boolean ("GUI", "ProcessingQueueEnbled"); - if (keyFile.has_key ("GUI", "ToolPanelsExpanded")) tpOpen = keyFile.get_integer_list ("GUI", "ToolPanelsExpanded"); - if (keyFile.has_key ("GUI", "MultiDisplayMode")) multiDisplayMode = keyFile.get_integer ("GUI", "MultiDisplayMode"); - //if (keyFile.has_key ("GUI", "CurvePanelsExpanded")) crvOpen = keyFile.get_integer_list ("GUI", "CurvePanelsExpanded"); - if (keyFile.has_key ("GUI", "CutOverlayBrush")) cutOverlayBrush = keyFile.get_double_list ("GUI", "CutOverlayBrush"); - if (keyFile.has_key ("GUI", "NavGuideBrush")) navGuideBrush = keyFile.get_double_list ("GUI", "NavGuideBrush"); - if (keyFile.has_key ("GUI", "HistogramPosition")) histogramPosition = keyFile.get_integer ("GUI", "HistogramPosition"); - if (keyFile.has_key ("GUI", "HistogramBar")) histogramBar = keyFile.get_boolean ("GUI", "HistogramBar"); - if (keyFile.has_key ("GUI", "HistogramFullMode")) histogramFullMode = keyFile.get_boolean ("GUI", "HistogramFullMode"); - if (keyFile.has_key ("GUI", "ShowFilmStripToolBar")) showFilmStripToolBar = keyFile.get_boolean ("GUI", "ShowFilmStripToolBar"); - if (keyFile.has_key ("GUI", "FileBrowserToolbarSingleRow")) FileBrowserToolbarSingleRow = keyFile.get_boolean ("GUI", "FileBrowserToolbarSingleRow"); - if (keyFile.has_key ("GUI", "HideTPVScrollbar")) hideTPVScrollbar = keyFile.get_boolean ("GUI", "HideTPVScrollbar"); - if (keyFile.has_key ("GUI", "UseIconNoText")) UseIconNoText = keyFile.get_boolean ("GUI", "UseIconNoText"); - if (keyFile.has_key ("GUI", "HistogramWorking")) rtSettings.HistogramWorking = keyFile.get_boolean ("GUI", "HistogramWorking"); - if (keyFile.has_key ("GUI", "CurveBBoxPosition")) curvebboxpos = keyFile.get_integer ("GUI", "CurveBBoxPosition"); -} - -if (keyFile.has_group ("Crop Settings")) { - if (keyFile.has_key ("Crop Settings", "PPI")) cropPPI = keyFile.get_integer ("Crop Settings", "PPI"); -} - -if (keyFile.has_group ("Color Management")) { - if (keyFile.has_key ("Color Management", "ICCDirectory")) rtSettings.iccDirectory = keyFile.get_string ("Color Management", "ICCDirectory"); - if (keyFile.has_key ("Color Management", "MonitorProfile")) rtSettings.monitorProfile = keyFile.get_string ("Color Management", "MonitorProfile"); - if (keyFile.has_key ("Color Management", "AutoMonitorProfile")) rtSettings.autoMonitorProfile = keyFile.get_boolean ("Color Management", "AutoMonitorProfile"); - if (keyFile.has_key ("Color Management", "Autocielab")) rtSettings.autocielab = keyFile.get_boolean ("Color Management", "Autocielab"); - if (keyFile.has_key ("Color Management", "RGBcurvesLumamode_Gamut")) rtSettings.rgbcurveslumamode_gamut = keyFile.get_boolean ("Color Management", "RGBcurvesLumamode_Gamut"); - - if (keyFile.has_key ("Color Management", "Intent")) rtSettings.colorimetricIntent = keyFile.get_integer("Color Management", "Intent"); - if (keyFile.has_key ("Color Management", "CRI")) rtSettings.CRI_color = keyFile.get_integer("Color Management", "CRI"); - if (keyFile.has_key ("Color Management", "DenoiseLabgamma"))rtSettings.denoiselabgamma = keyFile.get_integer("Color Management", "DenoiseLabgamma"); - if (keyFile.has_key ("Color Management", "view")) rtSettings.viewingdevice = keyFile.get_integer("Color Management", "view"); - if (keyFile.has_key ("Color Management", "grey")) rtSettings.viewingdevicegrey = keyFile.get_integer("Color Management", "grey"); - if (keyFile.has_key ("Color Management", "greySc")) rtSettings.viewinggreySc = keyFile.get_integer("Color Management", "greySc"); - if (keyFile.has_key ("Color Management", "CBDLArtif")) rtSettings.artifact_cbdl = keyFile.get_double("Color Management", "CBDLArtif"); - if (keyFile.has_key ("Color Management", "CBDLlevel0")) rtSettings.level0_cbdl = keyFile.get_double("Color Management", "CBDLlevel0"); - if (keyFile.has_key ("Color Management", "CBDLlevel123")) rtSettings.level123_cbdl = keyFile.get_double("Color Management", "CBDLlevel123"); - // if (keyFile.has_key ("Color Management", "Colortoningab")) rtSettings.colortoningab = keyFile.get_double("Color Management", "Colortoningab"); - // if (keyFile.has_key ("Color Management", "Decaction")) rtSettings.decaction = keyFile.get_double("Color Management", "Decaction"); - - if (keyFile.has_key ("Color Management", "WhiteBalanceSpotSize")) whiteBalanceSpotSize = keyFile.get_integer("Color Management", "WhiteBalanceSpotSize"); - if( keyFile.has_key ("Color Management", "GamutICC")) rtSettings.gamutICC = keyFile.get_boolean("Color Management", "GamutICC"); - // if( keyFile.has_key ("Color Management", "BWcomplement")) rtSettings.bw_complementary = keyFile.get_boolean("Color Management", "BWcomplement"); - if( keyFile.has_key ("Color Management", "Ciecamfloat")) rtSettings.ciecamfloat = keyFile.get_boolean("Color Management", "Ciecamfloat"); - if( keyFile.has_key ("Color Management", "AdobeRGB")) rtSettings.adobe = keyFile.get_string("Color Management", "AdobeRGB"); - if( keyFile.has_key ("Color Management", "ProPhoto")) rtSettings.prophoto = keyFile.get_string("Color Management", "ProPhoto"); - if( keyFile.has_key ("Color Management", "ProPhoto10")) rtSettings.prophoto10 = keyFile.get_string("Color Management", "ProPhoto10"); - if( keyFile.has_key ("Color Management", "WideGamut")) rtSettings.widegamut = keyFile.get_string("Color Management", "WideGamut"); - if( keyFile.has_key ("Color Management", "sRGB")) rtSettings.srgb = keyFile.get_string("Color Management", "sRGB"); - if( keyFile.has_key ("Color Management", "sRGB10")) rtSettings.srgb10 = keyFile.get_string("Color Management", "sRGB10"); - if( keyFile.has_key ("Color Management", "Beta")) rtSettings.beta = keyFile.get_string("Color Management", "Beta"); - if( keyFile.has_key ("Color Management", "Best")) rtSettings.best = keyFile.get_string("Color Management", "Best"); - if( keyFile.has_key ("Color Management", "Bruce")) rtSettings.bruce = keyFile.get_string("Color Management", "Bruce"); - if( keyFile.has_key ("Color Management", "GamutLch")) rtSettings.gamutLch = keyFile.get_boolean("Color Management", "GamutLch"); - if( keyFile.has_key ("Color Management", "ProtectRed")) rtSettings.protectred = keyFile.get_integer("Color Management", "ProtectRed"); - if( keyFile.has_key ("Color Management", "ProtectRedH")) rtSettings.protectredh = keyFile.get_double("Color Management", "ProtectRedH"); - if( keyFile.has_key ("Color Management", "Amountchroma")) rtSettings.amchroma = keyFile.get_integer("Color Management", "Amountchroma"); - - if( keyFile.has_key ("Color Management", "ClutsDirectory")) clutsDir = keyFile.get_string("Color Management", "ClutsDirectory"); -// if( keyFile.has_key ("Color Management", "Ciebadpixgauss")) rtSettings.ciebadpixgauss = keyFile.get_boolean("Color Management", "Ciebadpixgauss"); - -} - -if (keyFile.has_group ("Batch Processing")) { - if (keyFile.has_key ("Batch Processing", "AdjusterBehavior")) baBehav = keyFile.get_integer_list ("Batch Processing", "AdjusterBehavior"); -} - -if (keyFile.has_group ("Sounds")) { - if (keyFile.has_key ("Sounds", "Enable")) sndEnable = keyFile.get_boolean ("Sounds", "Enable"); - if (keyFile.has_key ("Sounds", "BatchQueueDone")) sndBatchQueueDone = keyFile.get_string ("Sounds", "BatchQueueDone"); - if (keyFile.has_key ("Sounds", "LngEditProcDone")) sndLngEditProcDone = keyFile.get_string ("Sounds", "LngEditProcDone"); - if (keyFile.has_key ("Sounds", "LngEditProcDoneSecs")) sndLngEditProcDoneSecs = keyFile.get_double ("Sounds", "LngEditProcDoneSecs"); -} - -if (keyFile.has_group ("Fast Export")) { - if (keyFile.has_key ("Fast Export", "fastexport_bypass_sharpening" )) fastexport_bypass_sharpening = keyFile.get_boolean ("Fast Export", "fastexport_bypass_sharpening" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_sharpenEdge" )) fastexport_bypass_sharpenEdge = keyFile.get_boolean ("Fast Export", "fastexport_bypass_sharpenEdge" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_sharpenMicro" )) fastexport_bypass_sharpenMicro = keyFile.get_boolean ("Fast Export", "fastexport_bypass_sharpenMicro" ); - //if (keyFile.has_key ("Fast Export", "fastexport_bypass_lumaDenoise" )) fastexport_bypass_lumaDenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_lumaDenoise" ); - //if (keyFile.has_key ("Fast Export", "fastexport_bypass_colorDenoise" )) fastexport_bypass_colorDenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_colorDenoise" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_defringe" )) fastexport_bypass_defringe = keyFile.get_boolean ("Fast Export", "fastexport_bypass_defringe" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_dirpyrDenoise" )) fastexport_bypass_dirpyrDenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_dirpyrDenoise" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_sh_hq" )) fastexport_bypass_sh_hq = keyFile.get_boolean ("Fast Export", "fastexport_bypass_sh_hq" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_dirpyrequalizer" )) fastexport_bypass_dirpyrequalizer = keyFile.get_boolean ("Fast Export", "fastexport_bypass_dirpyrequalizer" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_wavelet" )) fastexport_bypass_wavelet = keyFile.get_boolean ("Fast Export", "fastexport_bypass_wavelet" ); - if (keyFile.has_key ("Fast Export", "fastexport_raw_dmethod" )) fastexport_raw_bayer_method = keyFile.get_string ("Fast Export", "fastexport_raw_dmethod" ); - if (keyFile.has_key ("Fast Export", "fastexport_raw_bayer_method" )) fastexport_raw_bayer_method = keyFile.get_string ("Fast Export", "fastexport_raw_bayer_method" ); - //if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_all_enhance" )) fastexport_bypass_raw_bayer_all_enhance = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_all_enhance" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_dcb_iterations" )) fastexport_bypass_raw_bayer_dcb_iterations = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_dcb_iterations" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_dcb_iterations" )) fastexport_bypass_raw_bayer_dcb_iterations = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_bayer_dcb_iterations" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_dcb_enhance" )) fastexport_bypass_raw_bayer_dcb_enhance = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_dcb_enhance" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_dcb_enhance" )) fastexport_bypass_raw_bayer_dcb_enhance = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_bayer_dcb_enhance" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_lmmse_iterations" )) fastexport_bypass_raw_bayer_lmmse_iterations = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_lmmse_iterations" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_lmmse_iterations")) fastexport_bypass_raw_bayer_lmmse_iterations = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_bayer_lmmse_iterations"); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_linenoise" )) fastexport_bypass_raw_bayer_linenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_linenoise" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_linenoise" )) fastexport_bypass_raw_bayer_linenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_bayer_linenoise" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_greenthresh" )) fastexport_bypass_raw_bayer_greenthresh = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_greenthresh" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_greenthresh" )) fastexport_bypass_raw_bayer_greenthresh = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_bayer_greenthresh" ); - if (keyFile.has_key ("Fast Export", "fastexport_raw_xtrans_method" )) fastexport_raw_xtrans_method = keyFile.get_string ("Fast Export", "fastexport_raw_xtrans_method" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_ccSteps" )) fastexport_bypass_raw_ccSteps = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_ccSteps" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_ca" )) fastexport_bypass_raw_ca = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_ca" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_df" )) fastexport_bypass_raw_df = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_df" ); - if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_ff" )) fastexport_bypass_raw_ff = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_ff" ); - if (keyFile.has_key ("Fast Export", "fastexport_icm_input" )) fastexport_icm_input = keyFile.get_string ("Fast Export", "fastexport_icm_input" ); - if (keyFile.has_key ("Fast Export", "fastexport_icm_working" )) fastexport_icm_working = keyFile.get_string ("Fast Export", "fastexport_icm_working" ); - if (keyFile.has_key ("Fast Export", "fastexport_icm_output" )) fastexport_icm_output = keyFile.get_string ("Fast Export", "fastexport_icm_output" ); - if (keyFile.has_key ("Fast Export", "fastexport_icm_gamma" )) fastexport_icm_gamma = keyFile.get_string ("Fast Export", "fastexport_icm_gamma" ); - if (keyFile.has_key ("Fast Export", "fastexport_resize_enabled" )) fastexport_resize_enabled = keyFile.get_boolean ("Fast Export", "fastexport_resize_enabled" ); - if (keyFile.has_key ("Fast Export", "fastexport_resize_scale" )) fastexport_resize_scale = keyFile.get_double ("Fast Export", "fastexport_resize_scale" ); - if (keyFile.has_key ("Fast Export", "fastexport_resize_appliesTo" )) fastexport_resize_appliesTo = keyFile.get_string ("Fast Export", "fastexport_resize_appliesTo" ); - if (keyFile.has_key ("Fast Export", "fastexport_resize_method" )) fastexport_resize_method = keyFile.get_string ("Fast Export", "fastexport_resize_method" ); - if (keyFile.has_key ("Fast Export", "fastexport_resize_dataspec" )) fastexport_resize_dataspec = keyFile.get_integer ("Fast Export", "fastexport_resize_dataspec" ); - if (keyFile.has_key ("Fast Export", "fastexport_resize_width" )) fastexport_resize_width = keyFile.get_integer ("Fast Export", "fastexport_resize_width" ); - if (keyFile.has_key ("Fast Export", "fastexport_resize_height" )) fastexport_resize_height = keyFile.get_integer ("Fast Export", "fastexport_resize_height" ); -} - -if (keyFile.has_group ("Dialogs")) { - safeDirGet(keyFile, "Dialogs", "LastIccDir", lastIccDir); - safeDirGet(keyFile, "Dialogs", "LastDarkframeDir", lastDarkframeDir); - safeDirGet(keyFile, "Dialogs", "LastFlatfieldDir", lastFlatfieldDir); - safeDirGet(keyFile, "Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir); - safeDirGet(keyFile, "Dialogs", "LastLabCurvesDir", lastLabCurvesDir); - safeDirGet(keyFile, "Dialogs", "LastDenoiseCurvesDir", lastDenoiseCurvesDir); - safeDirGet(keyFile, "Dialogs", "LastWaveletCurvesDir", lastWaveletCurvesDir); - safeDirGet(keyFile, "Dialogs", "LastPFCurvesDir", lastPFCurvesDir); - safeDirGet(keyFile, "Dialogs", "LastHsvCurvesDir", lastHsvCurvesDir); - safeDirGet(keyFile, "Dialogs", "LastBWCurvesDir", lastBWCurvesDir); - - safeDirGet(keyFile, "Dialogs", "LastToneCurvesDir", lastToneCurvesDir); - safeDirGet(keyFile, "Dialogs", "LastVibranceCurvesDir", lastVibranceCurvesDir); - safeDirGet(keyFile, "Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir); -} - -// -------------------------------------------------------------------------------------------------------- - - filterOutParsedExtensions (); - - return 0; - - } - } - catch (Glib::Error &err) { - if (options.rtSettings.verbose) - printf("Options::readFromFile / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); - } - catch (...) { - if (options.rtSettings.verbose) - printf("Options::readFromFile / Unknown exception while trying to load \"%s\"!\n", fname.c_str()); - } - - return 1; - -} - -bool Options::safeDirGet(const rtengine::SafeKeyFile& keyFile, const Glib::ustring& section, - const Glib::ustring& entryName, Glib::ustring& destination) -{ - if (keyFile.has_key(section, entryName) && !keyFile.get_string(section, entryName).empty()) { - destination = keyFile.get_string(section, entryName); - return true; - } - return false; -} - -int Options::saveToFile (Glib::ustring fname) { - - rtengine::SafeKeyFile keyFile; - keyFile.set_boolean ("General", "TabbedEditor", tabbedUI); - - keyFile.set_boolean ("General", "StoreLastProfile", savesParamsAtExit); - if (startupDir==STARTUPDIR_HOME) - keyFile.set_string ("General", "StartupDirectory", "home"); - else if (startupDir==STARTUPDIR_CURRENT) - keyFile.set_string ("General", "StartupDirectory", "current"); - else if (startupDir==STARTUPDIR_CUSTOM) - keyFile.set_string ("General", "StartupDirectory", "custom"); - else if (startupDir==STARTUPDIR_LAST) - keyFile.set_string ("General", "StartupDirectory", "last"); - keyFile.set_string ("General", "StartupPath", startupPath); - keyFile.set_string ("General", "DateFormat", dateFormat); - keyFile.set_integer ("General", "AdjusterDelay", adjusterDelay); - keyFile.set_boolean ("General", "MultiUser", multiUser); - keyFile.set_string ("General", "Language", language); - keyFile.set_boolean ("General", "LanguageAutoDetect", languageAutoDetect); - keyFile.set_string ("General", "Theme", theme); - keyFile.set_boolean ("General", "SlimUI", slimUI); - keyFile.set_boolean ("General", "UseSystemTheme", useSystemTheme); - keyFile.set_string ("General", "Version", VERSION); - keyFile.set_string ("General", "DarkFramesPath", rtSettings.darkFramesPath); - keyFile.set_string ("General", "FlatFieldsPath", rtSettings.flatFieldsPath); - keyFile.set_boolean ("General", "Verbose", rtSettings.verbose); - keyFile.set_double ("General", "BotLeft", rtSettings.bot_left); - keyFile.set_double ("General", "TopLeft", rtSettings.top_left); - keyFile.set_double ("General", "TopRight", rtSettings.top_right); - keyFile.set_double ("General", "BotRight", rtSettings.bot_right); - keyFile.set_double ("General", "EDdetec", rtSettings.ed_detec); - keyFile.set_double ("General", "EDdetecStr", rtSettings.ed_detecStr); - keyFile.set_double ("General", "EDLow", rtSettings.ed_low); - keyFile.set_double ("General", "EDLipinfl", rtSettings.ed_lipinfl); - keyFile.set_double ("General", "EDLipampl", rtSettings.ed_lipampl); - - - keyFile.set_integer ("External Editor", "EditorKind", editorToSendTo); - keyFile.set_string ("External Editor", "GimpDir", gimpDir); - keyFile.set_string ("External Editor", "PhotoshopDir", psDir); - keyFile.set_string ("External Editor", "CustomEditor", customEditorProg); - - keyFile.set_boolean ("File Browser", "BrowseOnlyRaw", fbOnlyRaw); - keyFile.set_boolean ("File Browser", "BrowserShowsDate", fbShowDateTime); - keyFile.set_boolean ("File Browser", "BrowserShowsExif", fbShowBasicExif); - keyFile.set_boolean ("File Browser", "BrowserShowsExpComp", fbShowExpComp); - keyFile.set_boolean ("File Browser", "BrowserShowsHidden", fbShowHidden); - keyFile.set_integer ("File Browser", "ThumbnailSize", thumbSize); - keyFile.set_integer ("File Browser", "ThumbnailSizeTab", thumbSizeTab); - keyFile.set_integer ("File Browser", "ThumbnailSizeQueue", thumbSizeQueue); - keyFile.set_integer ("File Browser", "SameThumbSize", sameThumbSize); - keyFile.set_integer ("File Browser", "MaxPreviewHeight", maxThumbnailHeight); - keyFile.set_integer ("File Browser", "MaxCacheEntries", maxCacheEntries); - Glib::ArrayHandle pext = parseExtensions; - keyFile.set_string_list ("File Browser", "ParseExtensions", pext); - Glib::ArrayHandle pextena = parseExtensionsEnabled; - keyFile.set_integer_list ("File Browser", "ParseExtensionsEnabled", pextena); - keyFile.set_integer ("File Browser", "ThumbnailArrangement", fbArrangement); - keyFile.set_integer ("File Browser", "ThumbnailInterpolation", thumbInterp); - keyFile.set_boolean ("File Browser", "LiveThumbnails", liveThumbnails); - Glib::ArrayHandle pfav = favoriteDirs; - keyFile.set_string_list ("File Browser", "FavoriteDirs", pfav); - Glib::ArrayHandle pren = renameTemplates; - keyFile.set_string_list ("File Browser", "RenameTemplates", pren); - keyFile.set_boolean ("File Browser", "RenameUseTemplates", renameUseTemplates); - Glib::ArrayHandle ptzoom = thumbnailZoomRatios; - keyFile.set_double_list ("File Browser", "ThumbnailZoomRatios", ptzoom); - keyFile.set_boolean ("File Browser", "OverlayedFileNames", overlayedFileNames); - keyFile.set_boolean ("File Browser", "FilmStripOverlayedFileNames", filmStripOverlayedFileNames); - keyFile.set_boolean ("File Browser", "ShowFileNames", showFileNames ); - keyFile.set_boolean ("File Browser", "FilmStripShowFileNames", filmStripShowFileNames ); - keyFile.set_boolean ("File Browser", "InternalThumbIfUntouched", internalThumbIfUntouched ); - keyFile.set_boolean ("File Browser", "menuGroupRank", menuGroupRank); - keyFile.set_boolean ("File Browser", "menuGroupLabel", menuGroupLabel); - keyFile.set_boolean ("File Browser", "menuGroupFileOperations", menuGroupFileOperations); - keyFile.set_boolean ("File Browser", "menuGroupProfileOperations", menuGroupProfileOperations); + } + if( keyFile.has_key ("Performance", "NRWavlevel")) rtSettings.nrwavlevel = keyFile.get_integer ("Performance", "NRWavlevel"); + if (keyFile.has_key ("Performance", "LevNR")) rtSettings.leveldnv = keyFile.get_integer ("Performance", "LevNR"); + if (keyFile.has_key ("Performance", "LevNRTI")) rtSettings.leveldnti = keyFile.get_integer ("Performance", "LevNRTI"); + if (keyFile.has_key ("Performance", "LevNRAUT")) rtSettings.leveldnaut = keyFile.get_integer ("Performance", "LevNRAUT"); + if (keyFile.has_key ("Performance", "LevNRLISS")) rtSettings.leveldnliss = keyFile.get_integer ("Performance", "LevNRLISS"); + if (keyFile.has_key ("Performance", "SIMPLNRAUT")) rtSettings.leveldnautsimpl = keyFile.get_integer ("Performance", "SIMPLNRAUT"); + if (keyFile.has_key ("Performance", "ClutCacheSize")) clutCacheSize = keyFile.get_integer ("Performance", "ClutCacheSize"); + if (keyFile.has_key ("Performance", "MaxInspectorBuffers")) maxInspectorBuffers = keyFile.get_integer ("Performance", "MaxInspectorBuffers"); + if (keyFile.has_key ("Performance", "PreviewDemosaicFromSidecar")) prevdemo = (prevdemo_t)keyFile.get_integer ("Performance", "PreviewDemosaicFromSidecar"); + if (keyFile.has_key ("Performance", "Daubechies")) rtSettings.daubech = keyFile.get_boolean ("Performance", "Daubechies"); + if (keyFile.has_key ("Performance", "SerializeTiffRead")) serializeTiffRead = keyFile.get_boolean ("Performance", "SerializeTiffRead"); +} + +if (keyFile.has_group ("GUI")) { + if (keyFile.has_key ("GUI", "Font")) font = keyFile.get_string ("GUI", "Font"); + if (keyFile.has_key ("GUI", "WindowWidth")) windowWidth = keyFile.get_integer ("GUI", "WindowWidth"); + if (keyFile.has_key ("GUI", "WindowHeight")) windowHeight = keyFile.get_integer ("GUI", "WindowHeight"); + if (keyFile.has_key ("GUI", "WindowX")) windowX = keyFile.get_integer ("GUI", "WindowX"); + if (keyFile.has_key ("GUI", "WindowY")) windowY = keyFile.get_integer ("GUI", "WindowY"); + if (keyFile.has_key ("GUI", "WindowMaximized")) windowMaximized = keyFile.get_boolean ("GUI", "WindowMaximized"); + if (keyFile.has_key ("GUI", "DetailWindowWidth")) detailWindowWidth = keyFile.get_integer ("GUI", "DetailWindowWidth"); + if (keyFile.has_key ("GUI", "DetailWindowHeight")) detailWindowHeight = keyFile.get_integer ("GUI", "DetailWindowHeight"); + if (keyFile.has_key ("GUI", "DirBrowserWidth")) dirBrowserWidth = keyFile.get_integer ("GUI", "DirBrowserWidth"); + if (keyFile.has_key ("GUI", "DirBrowserHeight")) dirBrowserHeight = keyFile.get_integer ("GUI", "DirBrowserHeight"); + if (keyFile.has_key ("GUI", "SortType")) dirBrowserSortType = static_cast(keyFile.get_integer ("GUI", "SortType")); + if (keyFile.has_key ("GUI", "PreferencesWidth")) preferencesWidth = keyFile.get_integer ("GUI", "PreferencesWidth"); + if (keyFile.has_key ("GUI", "PreferencesHeight")) preferencesHeight = keyFile.get_integer ("GUI", "PreferencesHeight"); + if (keyFile.has_key ("GUI", "SaveAsDialogWidth")) saveAsDialogWidth = keyFile.get_integer ("GUI", "SaveAsDialogWidth"); + if (keyFile.has_key ("GUI", "SaveAsDialogHeight")) saveAsDialogHeight = keyFile.get_integer ("GUI", "SaveAsDialogHeight"); + if (keyFile.has_key ("GUI", "ToolPanelWidth")) toolPanelWidth = keyFile.get_integer ("GUI", "ToolPanelWidth"); + if (keyFile.has_key ("GUI", "BrowserToolPanelWidth")) browserToolPanelWidth = keyFile.get_integer ("GUI", "BrowserToolPanelWidth"); + if (keyFile.has_key ("GUI", "BrowserToolPanelHeight")) browserToolPanelHeight = keyFile.get_integer ("GUI", "BrowserToolPanelHeight"); + if (keyFile.has_key ("GUI", "BrowserToolPanelOpened")) browserToolPanelOpened = keyFile.get_boolean ("GUI", "BrowserToolPanelOpened"); + if (keyFile.has_key ("GUI", "BrowserDirPanelOpened")) browserDirPanelOpened = keyFile.get_boolean ("GUI", "BrowserDirPanelOpened"); + if (keyFile.has_key ("GUI", "EditorFilmStripOpened")) editorFilmStripOpened = keyFile.get_boolean ("GUI", "EditorFilmStripOpened"); + if (keyFile.has_key ("GUI", "HistoryPanelWidth")) historyPanelWidth = keyFile.get_integer ("GUI", "HistoryPanelWidth"); + if (keyFile.has_key ("GUI", "LastPreviewScale")) lastScale = keyFile.get_integer ("GUI", "LastPreviewScale"); + if (keyFile.has_key ("GUI", "PanAccelFactor")) panAccelFactor = keyFile.get_integer ("GUI", "PanAccelFactor"); + if (keyFile.has_key ("GUI", "RememberZoomAndPan")) rememberZoomAndPan = keyFile.get_boolean ("GUI", "RememberZoomAndPan"); + if (keyFile.has_key ("GUI", "LastCropSize")) lastCropSize = keyFile.get_integer ("GUI", "LastCropSize"); + if (keyFile.has_key ("GUI", "ShowHistory")) showHistory = keyFile.get_boolean ("GUI", "ShowHistory"); + if (keyFile.has_key ("GUI", "ShowFilePanelState")) showFilePanelState= keyFile.get_integer ("GUI", "ShowFilePanelState"); + if (keyFile.has_key ("GUI", "ShowInfo")) showInfo = keyFile.get_boolean ("GUI", "ShowInfo"); + if (keyFile.has_key ("GUI", "MainNBVertical")) mainNBVertical = keyFile.get_boolean ("GUI", "MainNBVertical"); + if (keyFile.has_key ("GUI", "ShowClippedHighlights"))showClippedHighlights = keyFile.get_boolean ("GUI", "ShowClippedHighlights"); + if (keyFile.has_key ("GUI", "ShowClippedShadows")) showClippedShadows= keyFile.get_boolean ("GUI", "ShowClippedShadows"); + if (keyFile.has_key ("GUI", "FrameColor")) bgcolor = keyFile.get_integer ("GUI", "FrameColor"); + if (keyFile.has_key ("GUI", "ProcessingQueueEnbled"))procQueueEnabled = keyFile.get_boolean ("GUI", "ProcessingQueueEnbled"); + if (keyFile.has_key ("GUI", "ToolPanelsExpanded")) tpOpen = keyFile.get_integer_list ("GUI", "ToolPanelsExpanded"); + if (keyFile.has_key ("GUI", "MultiDisplayMode")) multiDisplayMode = keyFile.get_integer ("GUI", "MultiDisplayMode"); + //if (keyFile.has_key ("GUI", "CurvePanelsExpanded")) crvOpen = keyFile.get_integer_list ("GUI", "CurvePanelsExpanded"); + if (keyFile.has_key ("GUI", "CutOverlayBrush")) cutOverlayBrush = keyFile.get_double_list ("GUI", "CutOverlayBrush"); + if (keyFile.has_key ("GUI", "NavGuideBrush")) navGuideBrush = keyFile.get_double_list ("GUI", "NavGuideBrush"); + if (keyFile.has_key ("GUI", "HistogramPosition")) histogramPosition = keyFile.get_integer ("GUI", "HistogramPosition"); + if (keyFile.has_key ("GUI", "HistogramBar")) histogramBar = keyFile.get_boolean ("GUI", "HistogramBar"); + if (keyFile.has_key ("GUI", "HistogramFullMode")) histogramFullMode = keyFile.get_boolean ("GUI", "HistogramFullMode"); + if (keyFile.has_key ("GUI", "ShowFilmStripToolBar")) showFilmStripToolBar = keyFile.get_boolean ("GUI", "ShowFilmStripToolBar"); + if (keyFile.has_key ("GUI", "FileBrowserToolbarSingleRow")) FileBrowserToolbarSingleRow = keyFile.get_boolean ("GUI", "FileBrowserToolbarSingleRow"); + if (keyFile.has_key ("GUI", "HideTPVScrollbar")) hideTPVScrollbar = keyFile.get_boolean ("GUI", "HideTPVScrollbar"); + if (keyFile.has_key ("GUI", "UseIconNoText")) UseIconNoText = keyFile.get_boolean ("GUI", "UseIconNoText"); + if (keyFile.has_key ("GUI", "HistogramWorking")) rtSettings.HistogramWorking = keyFile.get_boolean ("GUI", "HistogramWorking"); + if (keyFile.has_key ("GUI", "CurveBBoxPosition")) curvebboxpos = keyFile.get_integer ("GUI", "CurveBBoxPosition"); +} + +if (keyFile.has_group ("Crop Settings")) { + if (keyFile.has_key ("Crop Settings", "PPI")) cropPPI = keyFile.get_integer ("Crop Settings", "PPI"); +} + +if (keyFile.has_group ("Color Management")) { + if (keyFile.has_key ("Color Management", "ICCDirectory")) rtSettings.iccDirectory = keyFile.get_string ("Color Management", "ICCDirectory"); + if (keyFile.has_key ("Color Management", "MonitorProfile")) rtSettings.monitorProfile = keyFile.get_string ("Color Management", "MonitorProfile"); + if (keyFile.has_key ("Color Management", "AutoMonitorProfile")) rtSettings.autoMonitorProfile = keyFile.get_boolean ("Color Management", "AutoMonitorProfile"); + if (keyFile.has_key ("Color Management", "Autocielab")) rtSettings.autocielab = keyFile.get_boolean ("Color Management", "Autocielab"); + if (keyFile.has_key ("Color Management", "RGBcurvesLumamode_Gamut")) rtSettings.rgbcurveslumamode_gamut = keyFile.get_boolean ("Color Management", "RGBcurvesLumamode_Gamut"); + + if (keyFile.has_key ("Color Management", "Intent")) rtSettings.colorimetricIntent = keyFile.get_integer("Color Management", "Intent"); + if (keyFile.has_key ("Color Management", "CRI")) rtSettings.CRI_color = keyFile.get_integer("Color Management", "CRI"); + if (keyFile.has_key ("Color Management", "DenoiseLabgamma"))rtSettings.denoiselabgamma = keyFile.get_integer("Color Management", "DenoiseLabgamma"); + if (keyFile.has_key ("Color Management", "view")) rtSettings.viewingdevice = keyFile.get_integer("Color Management", "view"); + if (keyFile.has_key ("Color Management", "grey")) rtSettings.viewingdevicegrey = keyFile.get_integer("Color Management", "grey"); + if (keyFile.has_key ("Color Management", "greySc")) rtSettings.viewinggreySc = keyFile.get_integer("Color Management", "greySc"); + if (keyFile.has_key ("Color Management", "CBDLArtif")) rtSettings.artifact_cbdl = keyFile.get_double("Color Management", "CBDLArtif"); + if (keyFile.has_key ("Color Management", "CBDLlevel0")) rtSettings.level0_cbdl = keyFile.get_double("Color Management", "CBDLlevel0"); + if (keyFile.has_key ("Color Management", "CBDLlevel123")) rtSettings.level123_cbdl = keyFile.get_double("Color Management", "CBDLlevel123"); + // if (keyFile.has_key ("Color Management", "Colortoningab")) rtSettings.colortoningab = keyFile.get_double("Color Management", "Colortoningab"); + // if (keyFile.has_key ("Color Management", "Decaction")) rtSettings.decaction = keyFile.get_double("Color Management", "Decaction"); + + if (keyFile.has_key ("Color Management", "WhiteBalanceSpotSize")) whiteBalanceSpotSize = keyFile.get_integer("Color Management", "WhiteBalanceSpotSize"); + if( keyFile.has_key ("Color Management", "GamutICC")) rtSettings.gamutICC = keyFile.get_boolean("Color Management", "GamutICC"); + // if( keyFile.has_key ("Color Management", "BWcomplement")) rtSettings.bw_complementary = keyFile.get_boolean("Color Management", "BWcomplement"); + if( keyFile.has_key ("Color Management", "Ciecamfloat")) rtSettings.ciecamfloat = keyFile.get_boolean("Color Management", "Ciecamfloat"); + if( keyFile.has_key ("Color Management", "AdobeRGB")) rtSettings.adobe = keyFile.get_string("Color Management", "AdobeRGB"); + if( keyFile.has_key ("Color Management", "ProPhoto")) rtSettings.prophoto = keyFile.get_string("Color Management", "ProPhoto"); + if( keyFile.has_key ("Color Management", "ProPhoto10")) rtSettings.prophoto10 = keyFile.get_string("Color Management", "ProPhoto10"); + if( keyFile.has_key ("Color Management", "WideGamut")) rtSettings.widegamut = keyFile.get_string("Color Management", "WideGamut"); + if( keyFile.has_key ("Color Management", "sRGB")) rtSettings.srgb = keyFile.get_string("Color Management", "sRGB"); + if( keyFile.has_key ("Color Management", "sRGB10")) rtSettings.srgb10 = keyFile.get_string("Color Management", "sRGB10"); + if( keyFile.has_key ("Color Management", "Beta")) rtSettings.beta = keyFile.get_string("Color Management", "Beta"); + if( keyFile.has_key ("Color Management", "Best")) rtSettings.best = keyFile.get_string("Color Management", "Best"); + if( keyFile.has_key ("Color Management", "Bruce")) rtSettings.bruce = keyFile.get_string("Color Management", "Bruce"); + if( keyFile.has_key ("Color Management", "GamutLch")) rtSettings.gamutLch = keyFile.get_boolean("Color Management", "GamutLch"); + if( keyFile.has_key ("Color Management", "ProtectRed")) rtSettings.protectred = keyFile.get_integer("Color Management", "ProtectRed"); + if( keyFile.has_key ("Color Management", "ProtectRedH")) rtSettings.protectredh = keyFile.get_double("Color Management", "ProtectRedH"); + if( keyFile.has_key ("Color Management", "Amountchroma")) rtSettings.amchroma = keyFile.get_integer("Color Management", "Amountchroma"); + + if( keyFile.has_key ("Color Management", "ClutsDirectory")) clutsDir = keyFile.get_string("Color Management", "ClutsDirectory"); +// if( keyFile.has_key ("Color Management", "Ciebadpixgauss")) rtSettings.ciebadpixgauss = keyFile.get_boolean("Color Management", "Ciebadpixgauss"); + +} + +if (keyFile.has_group ("Batch Processing")) { + if (keyFile.has_key ("Batch Processing", "AdjusterBehavior")) baBehav = keyFile.get_integer_list ("Batch Processing", "AdjusterBehavior"); +} + +if (keyFile.has_group ("Sounds")) { + if (keyFile.has_key ("Sounds", "Enable")) sndEnable = keyFile.get_boolean ("Sounds", "Enable"); + if (keyFile.has_key ("Sounds", "BatchQueueDone")) sndBatchQueueDone = keyFile.get_string ("Sounds", "BatchQueueDone"); + if (keyFile.has_key ("Sounds", "LngEditProcDone")) sndLngEditProcDone = keyFile.get_string ("Sounds", "LngEditProcDone"); + if (keyFile.has_key ("Sounds", "LngEditProcDoneSecs")) sndLngEditProcDoneSecs = keyFile.get_double ("Sounds", "LngEditProcDoneSecs"); +} + +if (keyFile.has_group ("Fast Export")) { + if (keyFile.has_key ("Fast Export", "fastexport_bypass_sharpening" )) fastexport_bypass_sharpening = keyFile.get_boolean ("Fast Export", "fastexport_bypass_sharpening" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_sharpenEdge" )) fastexport_bypass_sharpenEdge = keyFile.get_boolean ("Fast Export", "fastexport_bypass_sharpenEdge" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_sharpenMicro" )) fastexport_bypass_sharpenMicro = keyFile.get_boolean ("Fast Export", "fastexport_bypass_sharpenMicro" ); + //if (keyFile.has_key ("Fast Export", "fastexport_bypass_lumaDenoise" )) fastexport_bypass_lumaDenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_lumaDenoise" ); + //if (keyFile.has_key ("Fast Export", "fastexport_bypass_colorDenoise" )) fastexport_bypass_colorDenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_colorDenoise" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_defringe" )) fastexport_bypass_defringe = keyFile.get_boolean ("Fast Export", "fastexport_bypass_defringe" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_dirpyrDenoise" )) fastexport_bypass_dirpyrDenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_dirpyrDenoise" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_sh_hq" )) fastexport_bypass_sh_hq = keyFile.get_boolean ("Fast Export", "fastexport_bypass_sh_hq" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_dirpyrequalizer" )) fastexport_bypass_dirpyrequalizer = keyFile.get_boolean ("Fast Export", "fastexport_bypass_dirpyrequalizer" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_wavelet" )) fastexport_bypass_wavelet = keyFile.get_boolean ("Fast Export", "fastexport_bypass_wavelet" ); + if (keyFile.has_key ("Fast Export", "fastexport_raw_dmethod" )) fastexport_raw_bayer_method = keyFile.get_string ("Fast Export", "fastexport_raw_dmethod" ); + if (keyFile.has_key ("Fast Export", "fastexport_raw_bayer_method" )) fastexport_raw_bayer_method = keyFile.get_string ("Fast Export", "fastexport_raw_bayer_method" ); + //if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_all_enhance" )) fastexport_bypass_raw_bayer_all_enhance = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_all_enhance" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_dcb_iterations" )) fastexport_bypass_raw_bayer_dcb_iterations = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_dcb_iterations" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_dcb_iterations" )) fastexport_bypass_raw_bayer_dcb_iterations = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_bayer_dcb_iterations" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_dcb_enhance" )) fastexport_bypass_raw_bayer_dcb_enhance = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_dcb_enhance" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_dcb_enhance" )) fastexport_bypass_raw_bayer_dcb_enhance = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_bayer_dcb_enhance" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_lmmse_iterations" )) fastexport_bypass_raw_bayer_lmmse_iterations = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_lmmse_iterations" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_lmmse_iterations")) fastexport_bypass_raw_bayer_lmmse_iterations = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_bayer_lmmse_iterations"); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_linenoise" )) fastexport_bypass_raw_bayer_linenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_linenoise" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_linenoise" )) fastexport_bypass_raw_bayer_linenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_bayer_linenoise" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_greenthresh" )) fastexport_bypass_raw_bayer_greenthresh = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_greenthresh" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_greenthresh" )) fastexport_bypass_raw_bayer_greenthresh = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_bayer_greenthresh" ); + if (keyFile.has_key ("Fast Export", "fastexport_raw_xtrans_method" )) fastexport_raw_xtrans_method = keyFile.get_string ("Fast Export", "fastexport_raw_xtrans_method" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_ccSteps" )) fastexport_bypass_raw_ccSteps = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_ccSteps" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_ca" )) fastexport_bypass_raw_ca = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_ca" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_df" )) fastexport_bypass_raw_df = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_df" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_ff" )) fastexport_bypass_raw_ff = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_ff" ); + if (keyFile.has_key ("Fast Export", "fastexport_icm_input" )) fastexport_icm_input = keyFile.get_string ("Fast Export", "fastexport_icm_input" ); + if (keyFile.has_key ("Fast Export", "fastexport_icm_working" )) fastexport_icm_working = keyFile.get_string ("Fast Export", "fastexport_icm_working" ); + if (keyFile.has_key ("Fast Export", "fastexport_icm_output" )) fastexport_icm_output = keyFile.get_string ("Fast Export", "fastexport_icm_output" ); + if (keyFile.has_key ("Fast Export", "fastexport_icm_gamma" )) fastexport_icm_gamma = keyFile.get_string ("Fast Export", "fastexport_icm_gamma" ); + if (keyFile.has_key ("Fast Export", "fastexport_resize_enabled" )) fastexport_resize_enabled = keyFile.get_boolean ("Fast Export", "fastexport_resize_enabled" ); + if (keyFile.has_key ("Fast Export", "fastexport_resize_scale" )) fastexport_resize_scale = keyFile.get_double ("Fast Export", "fastexport_resize_scale" ); + if (keyFile.has_key ("Fast Export", "fastexport_resize_appliesTo" )) fastexport_resize_appliesTo = keyFile.get_string ("Fast Export", "fastexport_resize_appliesTo" ); + if (keyFile.has_key ("Fast Export", "fastexport_resize_method" )) fastexport_resize_method = keyFile.get_string ("Fast Export", "fastexport_resize_method" ); + if (keyFile.has_key ("Fast Export", "fastexport_resize_dataspec" )) fastexport_resize_dataspec = keyFile.get_integer ("Fast Export", "fastexport_resize_dataspec" ); + if (keyFile.has_key ("Fast Export", "fastexport_resize_width" )) fastexport_resize_width = keyFile.get_integer ("Fast Export", "fastexport_resize_width" ); + if (keyFile.has_key ("Fast Export", "fastexport_resize_height" )) fastexport_resize_height = keyFile.get_integer ("Fast Export", "fastexport_resize_height" ); +} + +if (keyFile.has_group ("Dialogs")) { + safeDirGet(keyFile, "Dialogs", "LastIccDir", lastIccDir); + safeDirGet(keyFile, "Dialogs", "LastDarkframeDir", lastDarkframeDir); + safeDirGet(keyFile, "Dialogs", "LastFlatfieldDir", lastFlatfieldDir); + safeDirGet(keyFile, "Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastLabCurvesDir", lastLabCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastDenoiseCurvesDir", lastDenoiseCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastWaveletCurvesDir", lastWaveletCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastPFCurvesDir", lastPFCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastHsvCurvesDir", lastHsvCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastBWCurvesDir", lastBWCurvesDir); + + safeDirGet(keyFile, "Dialogs", "LastToneCurvesDir", lastToneCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastVibranceCurvesDir", lastVibranceCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir); +} + +// -------------------------------------------------------------------------------------------------------- + + filterOutParsedExtensions (); + + return 0; + + } + } + catch (Glib::Error &err) { + if (options.rtSettings.verbose) + printf("Options::readFromFile / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str()); + } + catch (...) { + if (options.rtSettings.verbose) + printf("Options::readFromFile / Unknown exception while trying to load \"%s\"!\n", fname.c_str()); + } + + return 1; + +} + +bool Options::safeDirGet(const rtengine::SafeKeyFile& keyFile, const Glib::ustring& section, + const Glib::ustring& entryName, Glib::ustring& destination) +{ + if (keyFile.has_key(section, entryName) && !keyFile.get_string(section, entryName).empty()) { + destination = keyFile.get_string(section, entryName); + return true; + } + return false; +} + +int Options::saveToFile (Glib::ustring fname) { + + rtengine::SafeKeyFile keyFile; + keyFile.set_boolean ("General", "TabbedEditor", tabbedUI); + + keyFile.set_boolean ("General", "StoreLastProfile", savesParamsAtExit); + if (startupDir==STARTUPDIR_HOME) + keyFile.set_string ("General", "StartupDirectory", "home"); + else if (startupDir==STARTUPDIR_CURRENT) + keyFile.set_string ("General", "StartupDirectory", "current"); + else if (startupDir==STARTUPDIR_CUSTOM) + keyFile.set_string ("General", "StartupDirectory", "custom"); + else if (startupDir==STARTUPDIR_LAST) + keyFile.set_string ("General", "StartupDirectory", "last"); + keyFile.set_string ("General", "StartupPath", startupPath); + keyFile.set_string ("General", "DateFormat", dateFormat); + keyFile.set_integer ("General", "AdjusterDelay", adjusterDelay); + keyFile.set_boolean ("General", "MultiUser", multiUser); + keyFile.set_string ("General", "Language", language); + keyFile.set_boolean ("General", "LanguageAutoDetect", languageAutoDetect); + keyFile.set_string ("General", "Theme", theme); + keyFile.set_boolean ("General", "SlimUI", slimUI); + keyFile.set_boolean ("General", "UseSystemTheme", useSystemTheme); + keyFile.set_string ("General", "Version", VERSION); + keyFile.set_string ("General", "DarkFramesPath", rtSettings.darkFramesPath); + keyFile.set_string ("General", "FlatFieldsPath", rtSettings.flatFieldsPath); + keyFile.set_boolean ("General", "Verbose", rtSettings.verbose); + keyFile.set_double ("General", "BotLeft", rtSettings.bot_left); + keyFile.set_double ("General", "TopLeft", rtSettings.top_left); + keyFile.set_double ("General", "TopRight", rtSettings.top_right); + keyFile.set_double ("General", "BotRight", rtSettings.bot_right); + keyFile.set_double ("General", "EDdetec", rtSettings.ed_detec); + keyFile.set_double ("General", "EDdetecStr", rtSettings.ed_detecStr); + keyFile.set_double ("General", "EDLow", rtSettings.ed_low); + keyFile.set_double ("General", "EDLipinfl", rtSettings.ed_lipinfl); + keyFile.set_double ("General", "EDLipampl", rtSettings.ed_lipampl); + + + keyFile.set_integer ("External Editor", "EditorKind", editorToSendTo); + keyFile.set_string ("External Editor", "GimpDir", gimpDir); + keyFile.set_string ("External Editor", "PhotoshopDir", psDir); + keyFile.set_string ("External Editor", "CustomEditor", customEditorProg); + + keyFile.set_boolean ("File Browser", "BrowseOnlyRaw", fbOnlyRaw); + keyFile.set_boolean ("File Browser", "BrowserShowsDate", fbShowDateTime); + keyFile.set_boolean ("File Browser", "BrowserShowsExif", fbShowBasicExif); + keyFile.set_boolean ("File Browser", "BrowserShowsExpComp", fbShowExpComp); + keyFile.set_boolean ("File Browser", "BrowserShowsHidden", fbShowHidden); + keyFile.set_integer ("File Browser", "ThumbnailSize", thumbSize); + keyFile.set_integer ("File Browser", "ThumbnailSizeTab", thumbSizeTab); + keyFile.set_integer ("File Browser", "ThumbnailSizeQueue", thumbSizeQueue); + keyFile.set_integer ("File Browser", "SameThumbSize", sameThumbSize); + keyFile.set_integer ("File Browser", "MaxPreviewHeight", maxThumbnailHeight); + keyFile.set_integer ("File Browser", "MaxCacheEntries", maxCacheEntries); + Glib::ArrayHandle pext = parseExtensions; + keyFile.set_string_list ("File Browser", "ParseExtensions", pext); + Glib::ArrayHandle pextena = parseExtensionsEnabled; + keyFile.set_integer_list ("File Browser", "ParseExtensionsEnabled", pextena); + keyFile.set_integer ("File Browser", "ThumbnailArrangement", fbArrangement); + keyFile.set_integer ("File Browser", "ThumbnailInterpolation", thumbInterp); + keyFile.set_boolean ("File Browser", "LiveThumbnails", liveThumbnails); + Glib::ArrayHandle pfav = favoriteDirs; + keyFile.set_string_list ("File Browser", "FavoriteDirs", pfav); + Glib::ArrayHandle pren = renameTemplates; + keyFile.set_string_list ("File Browser", "RenameTemplates", pren); + keyFile.set_boolean ("File Browser", "RenameUseTemplates", renameUseTemplates); + Glib::ArrayHandle ptzoom = thumbnailZoomRatios; + keyFile.set_double_list ("File Browser", "ThumbnailZoomRatios", ptzoom); + keyFile.set_boolean ("File Browser", "OverlayedFileNames", overlayedFileNames); + keyFile.set_boolean ("File Browser", "FilmStripOverlayedFileNames", filmStripOverlayedFileNames); + keyFile.set_boolean ("File Browser", "ShowFileNames", showFileNames ); + keyFile.set_boolean ("File Browser", "FilmStripShowFileNames", filmStripShowFileNames ); + keyFile.set_boolean ("File Browser", "InternalThumbIfUntouched", internalThumbIfUntouched ); + keyFile.set_boolean ("File Browser", "menuGroupRank", menuGroupRank); + keyFile.set_boolean ("File Browser", "menuGroupLabel", menuGroupLabel); + keyFile.set_boolean ("File Browser", "menuGroupFileOperations", menuGroupFileOperations); + keyFile.set_boolean ("File Browser", "menuGroupProfileOperations", menuGroupProfileOperations); keyFile.set_boolean ("File Browser", "menuGroupExtProg", menuGroupExtProg); keyFile.set_integer ("File Browser", "MaxRecentFolders", maxRecentFolders); { @@ -1096,407 +1096,407 @@ int Options::saveToFile (Glib::ustring fname) { temp.reserve(maxRecentFolders); for(unsigned int i=0;i tpopen = tpOpen; - keyFile.set_integer_list ("GUI", "ToolPanelsExpanded", tpopen); - keyFile.set_integer ("GUI", "MultiDisplayMode", multiDisplayMode); - keyFile.set_double_list ("GUI", "CutOverlayBrush", cutOverlayBrush); - keyFile.set_double_list ("GUI", "NavGuideBrush", navGuideBrush); - keyFile.set_integer ("GUI", "HistogramPosition", histogramPosition); - keyFile.set_boolean ("GUI", "HistogramBar", histogramBar); - keyFile.set_boolean ("GUI", "HistogramFullMode", histogramFullMode); - keyFile.set_boolean ("GUI", "ShowFilmStripToolBar", showFilmStripToolBar); - keyFile.set_boolean ("GUI", "FileBrowserToolbarSingleRow", FileBrowserToolbarSingleRow); - keyFile.set_boolean ("GUI", "HideTPVScrollbar", hideTPVScrollbar); - keyFile.set_boolean ("GUI", "UseIconNoText", UseIconNoText); - keyFile.set_boolean ("GUI", "HistogramWorking", rtSettings.HistogramWorking); - keyFile.set_integer ("GUI", "CurveBBoxPosition", curvebboxpos); - - //Glib::ArrayHandle crvopen = crvOpen; - //keyFile.set_integer_list ("GUI", "CurvePanelsExpanded", crvopen); - - keyFile.set_integer ("Crop Settings", "PPI", cropPPI); - - keyFile.set_string ("Color Management", "ICCDirectory", rtSettings.iccDirectory); - keyFile.set_string ("Color Management", "MonitorProfile", rtSettings.monitorProfile); - keyFile.set_boolean ("Color Management", "AutoMonitorProfile", rtSettings.autoMonitorProfile); - keyFile.set_boolean ("Color Management", "Autocielab", rtSettings.autocielab); - keyFile.set_boolean ("Color Management", "RGBcurvesLumamode_Gamut", rtSettings.rgbcurveslumamode_gamut); - keyFile.set_integer ("Color Management", "Intent", rtSettings.colorimetricIntent); - keyFile.set_integer ("Color Management", "view", rtSettings.viewingdevice); - keyFile.set_integer ("Color Management", "grey", rtSettings.viewingdevicegrey); - keyFile.set_integer ("Color Management", "greySc", rtSettings.viewinggreySc); - - keyFile.set_string ("Color Management", "AdobeRGB", rtSettings.adobe); - keyFile.set_string ("Color Management", "ProPhoto", rtSettings.prophoto); - keyFile.set_string ("Color Management", "ProPhoto10", rtSettings.prophoto10); - keyFile.set_string ("Color Management", "WideGamut", rtSettings.widegamut); - keyFile.set_string ("Color Management", "sRGB", rtSettings.srgb); - keyFile.set_string ("Color Management", "sRGB10", rtSettings.srgb10); - keyFile.set_string ("Color Management", "Beta", rtSettings.beta); - keyFile.set_string ("Color Management", "Best", rtSettings.best); - keyFile.set_string ("Color Management", "Bruce", rtSettings.bruce); - keyFile.set_integer ("Color Management", "WhiteBalanceSpotSize", whiteBalanceSpotSize); - keyFile.set_boolean ("Color Management", "GamutICC", rtSettings.gamutICC); - // keyFile.set_boolean ("Color Management", "BWcomplement", rtSettings.bw_complementary); - keyFile.set_boolean ("Color Management", "Ciecamfloat", rtSettings.ciecamfloat); - keyFile.set_boolean ("Color Management", "GamutLch", rtSettings.gamutLch); - keyFile.set_integer ("Color Management", "ProtectRed", rtSettings.protectred); - keyFile.set_integer ("Color Management", "Amountchroma", rtSettings.amchroma); - keyFile.set_double ("Color Management", "ProtectRedH", rtSettings.protectredh); - keyFile.set_integer ("Color Management", "CRI", rtSettings.CRI_color); - keyFile.set_integer ("Color Management", "DenoiseLabgamma", rtSettings.denoiselabgamma); -// keyFile.set_boolean ("Color Management", "Ciebadpixgauss", rtSettings.ciebadpixgauss); - keyFile.set_double ("Color Management", "CBDLArtif", rtSettings.artifact_cbdl); - keyFile.set_double ("Color Management", "CBDLlevel0", rtSettings.level0_cbdl); - keyFile.set_double ("Color Management", "CBDLlevel123", rtSettings.level123_cbdl); - // keyFile.set_double ("Color Management", "Colortoningab", rtSettings.colortoningab); -// keyFile.set_double ("Color Management", "Decaction", rtSettings.decaction); - keyFile.set_string ("Color Management", "ClutsDirectory", clutsDir); - - - Glib::ArrayHandle bab = baBehav; - keyFile.set_integer_list ("Batch Processing", "AdjusterBehavior", bab); - - keyFile.set_boolean ("Sounds", "Enable", sndEnable); - keyFile.set_string ("Sounds", "BatchQueueDone", sndBatchQueueDone); - keyFile.set_string ("Sounds", "LngEditProcDone", sndLngEditProcDone); - keyFile.set_double ("Sounds", "LngEditProcDoneSecs", sndLngEditProcDoneSecs); - - - keyFile.set_boolean ("Fast Export", "fastexport_bypass_sharpening" , fastexport_bypass_sharpening ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_sharpenEdge" , fastexport_bypass_sharpenEdge ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_sharpenMicro" , fastexport_bypass_sharpenMicro ); - //keyFile.set_boolean ("Fast Export", "fastexport_bypass_lumaDenoise" , fastexport_bypass_lumaDenoise ); - //keyFile.set_boolean ("Fast Export", "fastexport_bypass_colorDenoise" , fastexport_bypass_colorDenoise ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_defringe" , fastexport_bypass_defringe ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_dirpyrDenoise" , fastexport_bypass_dirpyrDenoise ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_sh_hq" , fastexport_bypass_sh_hq ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_dirpyrequalizer" , fastexport_bypass_dirpyrequalizer ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_wavelet" , fastexport_bypass_wavelet ); - keyFile.set_string ("Fast Export", "fastexport_raw_bayer_method" , fastexport_raw_bayer_method ); - //keyFile.set_boolean ("Fast Export", "fastexport_bypass_bayer_raw_all_enhance" , fastexport_bypass_raw_bayer_all_enhance ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_dcb_iterations" , fastexport_bypass_raw_bayer_dcb_iterations ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_dcb_enhance" , fastexport_bypass_raw_bayer_dcb_enhance ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_lmmse_iterations", fastexport_bypass_raw_bayer_lmmse_iterations); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_linenoise" , fastexport_bypass_raw_bayer_linenoise ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_greenthresh" , fastexport_bypass_raw_bayer_greenthresh ); - keyFile.set_string ("Fast Export", "fastexport_raw_xtrans_method" , fastexport_raw_xtrans_method ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_ccSteps" , fastexport_bypass_raw_ccSteps ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_ca" , fastexport_bypass_raw_ca ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_df" , fastexport_bypass_raw_df ); - keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_ff" , fastexport_bypass_raw_ff ); - keyFile.set_string ("Fast Export", "fastexport_icm_input" , fastexport_icm_input ); - keyFile.set_string ("Fast Export", "fastexport_icm_working" , fastexport_icm_working ); - keyFile.set_string ("Fast Export", "fastexport_icm_output" , fastexport_icm_output ); - keyFile.set_string ("Fast Export", "fastexport_icm_gamma" , fastexport_icm_gamma ); - keyFile.set_boolean ("Fast Export", "fastexport_resize_enabled" , fastexport_resize_enabled ); - keyFile.set_double ("Fast Export", "fastexport_resize_scale" , fastexport_resize_scale ); - keyFile.set_string ("Fast Export", "fastexport_resize_appliesTo" , fastexport_resize_appliesTo ); - keyFile.set_string ("Fast Export", "fastexport_resize_method" , fastexport_resize_method ); - keyFile.set_integer ("Fast Export", "fastexport_resize_dataspec" , fastexport_resize_dataspec ); - keyFile.set_integer ("Fast Export", "fastexport_resize_width" , fastexport_resize_width ); - keyFile.set_integer ("Fast Export", "fastexport_resize_height" , fastexport_resize_height ); - - keyFile.set_string ("Dialogs", "LastIccDir", lastIccDir); - keyFile.set_string ("Dialogs", "LastDarkframeDir", lastDarkframeDir); - keyFile.set_string ("Dialogs", "LastFlatfieldDir", lastFlatfieldDir); - keyFile.set_string ("Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir); - keyFile.set_string ("Dialogs", "LastLabCurvesDir", lastLabCurvesDir); - keyFile.set_string ("Dialogs", "LastDenoiseCurvesDir", lastDenoiseCurvesDir); - keyFile.set_string ("Dialogs", "LastWaveletCurvesDir", lastWaveletCurvesDir); - keyFile.set_string ("Dialogs", "LastPFCurvesDir", lastPFCurvesDir); - keyFile.set_string ("Dialogs", "LastHsvCurvesDir", lastHsvCurvesDir); - keyFile.set_string ("Dialogs", "LastBWCurvesDir", lastBWCurvesDir); - keyFile.set_string ("Dialogs", "LastToneCurvesDir", lastToneCurvesDir); - keyFile.set_string ("Dialogs", "LastVibranceCurvesDir", lastVibranceCurvesDir); - keyFile.set_string ("Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir); - - FILE *f = safe_g_fopen (fname, "wt"); - if (f==NULL) { - if (options.rtSettings.verbose) - printf("Options::saveToFile / Error: unable to open file \"%s\" with write access!\n", fname.c_str()); - return 1; - } - else { - fprintf (f, "%s", keyFile.to_data().c_str()); - fclose (f); - return 0; - } -} - -bool Options::load () { - - // Find the application data path - - const gchar* path; - Glib::ustring dPath; - - path = g_getenv("RT_SETTINGS"); - if (path != NULL) { - rtdir = Glib::ustring(path); - if (!Glib::path_is_absolute(rtdir)) - return false; - } - else { - #ifdef WIN32 - WCHAR pathW[MAX_PATH]={0}; char pathA[MAX_PATH]; - - if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_LOCAL_APPDATA,false)) { - WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); - rtdir = Glib::build_filename(Glib::ustring(pathA), Glib::ustring(CACHEFOLDERNAME)); - } - #else - rtdir = Glib::build_filename(Glib::ustring(g_get_user_config_dir ()), Glib::ustring(CACHEFOLDERNAME)); - #endif - } - - if (options.rtSettings.verbose) - printf("Settings directory (rtdir) = %s\n", rtdir.c_str()); - - // Set the cache folder in RT's base folder - cacheBaseDir = Glib::build_filename(argv0, "cache"); - - // Read the global option file (the one located in the application's base folder) - options.readFromFile (Glib::build_filename(argv0, "options")); - - // Modify the path of the cache folder to the one provided in RT_CACHE environment variable - path = g_getenv("RT_CACHE"); - if (path != NULL) { - cacheBaseDir = Glib::ustring(path); - if (!Glib::path_is_absolute(cacheBaseDir)) - return false; - } - // No environment variable provided, so falling back to the multi user mode, is enabled - else if (options.multiUser) { - #ifdef WIN32 - cacheBaseDir = Glib::build_filename(rtdir, "cache"); - #else - cacheBaseDir = Glib::build_filename(Glib::ustring(g_get_user_cache_dir()), Glib::ustring(CACHEFOLDERNAME)); - #endif - } - - // Check if RT is installed in Multi-User mode - if (options.multiUser) { - // Read the user option file (the one located somewhere in the user's home folder) - // Those values supersets those of the global option file - int r = options.readFromFile (Glib::build_filename(rtdir, "options")); - // If the local option file does not exist or is broken, and the local cache folder does not exist, recreate it - if (r && !safe_g_mkdir_with_parents (rtdir, 511)) { - // Save the option file - options.saveToFile (Glib::build_filename(rtdir, "options")); - } - -#ifdef __APPLE__ - // make sure .local/share exists on OS X so we don't get problems with recently-used.xbel - safe_g_mkdir_with_parents (g_get_user_data_dir(), 511); -#endif - } - - if (options.rtSettings.verbose) - printf("Cache directory (cacheBaseDir) = %s\n", cacheBaseDir.c_str()); - - // Update profile's path and recreate it if necessary - options.updatePaths(); - - // Check default Raw and Img procparams existence - if (options.defProfRaw.empty()) - options.defProfRaw = DEFPROFILE_INTERNAL; - else { - Glib::ustring tmpFName = options.findProfilePath(options.defProfRaw); - if (!tmpFName.empty()) { - if (options.rtSettings.verbose) printf("Raws' default profile \"%s\" found\n", options.defProfRaw.c_str()); - } - else { - if (options.rtSettings.verbose) printf("Raws' default profile \"%s\" not found or not set -> using Internal values\n", options.defProfRaw.c_str()); - options.defProfRaw = DEFPROFILE_INTERNAL; - options.defProfRawMissing = true; - } - } - - if (options.defProfImg.empty()) - options.defProfImg = DEFPROFILE_INTERNAL; - else { - Glib::ustring tmpFName = options.findProfilePath(options.defProfImg); - if (!tmpFName.empty()) { - if (options.rtSettings.verbose) printf("Images' default profile \"%s\" found\n", options.defProfImg.c_str()); - } - else { - if (options.rtSettings.verbose) printf("Images' default profile \"%s\" not found or not set -> using Internal values\n", options.defProfImg.c_str()); - options.defProfImg = DEFPROFILE_INTERNAL; - options.defProfImgMissing = true; - } - } - - //We handle languages using a hierarchy of translations. The top of the hierarchy is default. This includes a default translation for all items - // (most likely using simple English). The next level is the language: for instance, English, French, Chinese, etc. This file should contain a - // generic translation for all items which differ from default. Finally there is the locale. This is region-specific items which differ from the - // language file. These files must be name in the format (), where Language is the name of the language which it inherits from, - // and LC is the local code. Some examples of this would be English (US) (American English), French (FR) (Franch French), French (CA) (Canadian - // French), etc. - // - // Each level will only contain the differences between itself and its parent translation. For instance, English (UK) or English (CA) may - // include the translation "HISTORY_MSG_34;Avoid Colour Clipping" where English would translate it as "HISTORY_MSG_34;Avoid Color Clipping" (note - // the difference in the spelling of 'colour'). - // - // It is important that when naming the translation files, that you stick to the format or (). We depend on that to figure - // out which are the parent translations. Furthermore, there must be a file for each locale () -- you cannot have - // 'French (CA)' unless there is a file 'French'. - - Glib::ustring defaultTranslation = argv0 + "/languages/default"; - Glib::ustring languageTranslation = ""; - Glib::ustring localeTranslation = ""; - - if (options.languageAutoDetect) options.language=langMgr.getOSUserLanguage(); - - if (!options.language.empty()){ - std::vector langPortions = Glib::Regex::split_simple(" ", options.language); - if (langPortions.size() >= 1){ - languageTranslation = argv0 + "/languages/" + langPortions.at(0); - } - if (langPortions.size() >= 2){ - localeTranslation = argv0 + "/languages/" + options.language; - } - } - - langMgr.load(localeTranslation, new MultiLangMgr(languageTranslation, new MultiLangMgr(defaultTranslation))); - - rtengine::init (&options.rtSettings, argv0, rtdir); - - return true; -} - -void Options::save () { - - if (options.multiUser==false) { - options.saveToFile (Glib::build_filename(argv0, "options")); - } - else { - options.saveToFile (Glib::build_filename(rtdir, "options")); - } -} - -/* - * return true if fname ends with one of the retained image file extensions - */ -bool Options::has_retained_extention (Glib::ustring fname) { - - Glib::ustring ext = getExtension(fname).lowercase(); - - if (!ext.empty()) { - // there is an extension to the filename - - // look out if it has one of the retained extensions - for (unsigned int i=0; i=(int)parseExtensionsEnabled.size() || parseExtensionsEnabled[j]; - return false; -} + keyFile.set_string_list ("File Browser", "RecentFolders", temp); + } + keyFile.set_integer ("Clipping Indication", "HighlightThreshold", highlightThreshold); + keyFile.set_integer ("Clipping Indication", "ShadowThreshold", shadowThreshold); + keyFile.set_boolean ("Clipping Indication", "BlinkClipped", blinkClipped); + + keyFile.set_integer ("Performance", "RgbDenoiseThreadLimit", rgbDenoiseThreadLimit); + keyFile.set_double ("Performance", "NRauto", rtSettings.nrauto); + keyFile.set_double ("Performance", "NRautomax", rtSettings.nrautomax); + keyFile.set_double ("Performance", "NRhigh", rtSettings.nrhigh); + keyFile.set_integer ("Performance", "NRWavlevel", rtSettings.nrwavlevel); + keyFile.set_integer ("Performance", "LevNR", rtSettings.leveldnv); + keyFile.set_integer ("Performance", "LevNRTI", rtSettings.leveldnti); + keyFile.set_integer ("Performance", "LevNRAUT", rtSettings.leveldnaut); + keyFile.set_integer ("Performance", "LevNRLISS", rtSettings.leveldnliss); + keyFile.set_integer ("Performance", "SIMPLNRAUT", rtSettings.leveldnautsimpl); + keyFile.set_integer ("Performance", "ClutCacheSize", clutCacheSize); + keyFile.set_integer ("Performance", "MaxInspectorBuffers", maxInspectorBuffers); + keyFile.set_integer ("Performance", "PreviewDemosaicFromSidecar", prevdemo); + keyFile.set_boolean ("Performance", "Daubechies", rtSettings.daubech); + keyFile.set_boolean ("Performance", "SerializeTiffRead", serializeTiffRead); + + keyFile.set_string ("Output", "Format", saveFormat.format); + keyFile.set_integer ("Output", "JpegQuality", saveFormat.jpegQuality); + keyFile.set_integer ("Output", "JpegSubSamp", saveFormat.jpegSubSamp); + keyFile.set_integer ("Output", "PngCompression", saveFormat.pngCompression); + keyFile.set_integer ("Output", "PngBps", saveFormat.pngBits); + keyFile.set_integer ("Output", "TiffBps", saveFormat.tiffBits); + keyFile.set_boolean ("Output", "TiffUncompressed", saveFormat.tiffUncompressed); + keyFile.set_boolean ("Output", "SaveProcParams", saveFormat.saveParams); + + keyFile.set_string ("Output", "FormatBatch", saveFormatBatch.format); + keyFile.set_integer ("Output", "JpegQualityBatch", saveFormatBatch.jpegQuality); + keyFile.set_integer ("Output", "JpegSubSampBatch", saveFormatBatch.jpegSubSamp); + keyFile.set_integer ("Output", "PngCompressionBatch", saveFormatBatch.pngCompression); + keyFile.set_integer ("Output", "PngBpsBatch", saveFormatBatch.pngBits); + keyFile.set_integer ("Output", "TiffBpsBatch", saveFormatBatch.tiffBits); + keyFile.set_boolean ("Output", "TiffUncompressedBatch", saveFormatBatch.tiffUncompressed); + keyFile.set_boolean ("Output", "SaveProcParamsBatch", saveFormatBatch.saveParams); + + keyFile.set_string ("Output", "PathTemplate", savePathTemplate); + keyFile.set_string ("Output", "PathFolder", savePathFolder); + keyFile.set_boolean ("Output", "AutoSuffix", autoSuffix); + keyFile.set_boolean ("Output", "ForceFormatOpts", forceFormatOpts); + keyFile.set_integer ("Output", "SaveMethodNum", saveMethodNum); + keyFile.set_boolean ("Output", "UsePathTemplate", saveUsePathTemplate); + keyFile.set_string ("Output", "LastSaveAsPath", lastSaveAsPath); + keyFile.set_boolean ("Output", "OverwriteOutputFile", overwriteOutputFile); + keyFile.set_boolean ("Output", "TunnelMetaData", tunnelMetaData); + + keyFile.set_string ("Profiles", "Directory", profilePath); + keyFile.set_boolean ("Profiles", "UseBundledProfiles", useBundledProfiles); + keyFile.set_string ("Profiles", "LoadSaveProfilePath", loadSaveProfilePath); + keyFile.set_string ("Profiles", "RawDefault", defProfRaw); + keyFile.set_string ("Profiles", "ImgDefault", defProfImg); + keyFile.set_boolean ("Profiles", "FilledProfile", filledProfile); + keyFile.set_boolean ("Profiles", "SaveParamsWithFile", saveParamsFile); + keyFile.set_boolean ("Profiles", "SaveParamsToCache", saveParamsCache); + keyFile.set_integer ("Profiles", "LoadParamsFromLocation", paramsLoadLocation); + keyFile.set_string ("Profiles", "CustomProfileBuilderPath", CPBPath); + keyFile.set_integer ("Profiles", "CustomProfileBuilderKeys", CPBKeys); + + keyFile.set_string ("GUI", "Font", font); + keyFile.set_integer ("GUI", "WindowWidth", windowWidth); + keyFile.set_integer ("GUI", "WindowHeight", windowHeight); + keyFile.set_integer ("GUI", "WindowX", windowX); + keyFile.set_integer ("GUI", "WindowY", windowY); + keyFile.set_boolean ("GUI", "WindowMaximized", windowMaximized); + keyFile.set_integer ("GUI", "DetailWindowWidth", detailWindowWidth); + keyFile.set_integer ("GUI", "DetailWindowHeight", detailWindowHeight); + keyFile.set_integer ("GUI", "DirBrowserWidth", dirBrowserWidth); + keyFile.set_integer ("GUI", "DirBrowserHeight", dirBrowserHeight); + keyFile.set_integer ("GUI", "SortType", dirBrowserSortType); + keyFile.set_integer ("GUI", "PreferencesWidth", preferencesWidth); + keyFile.set_integer ("GUI", "PreferencesHeight", preferencesHeight); + keyFile.set_integer ("GUI", "SaveAsDialogWidth", saveAsDialogWidth); + keyFile.set_integer ("GUI", "SaveAsDialogHeight", saveAsDialogHeight); + keyFile.set_integer ("GUI", "ToolPanelWidth", toolPanelWidth); + keyFile.set_integer ("GUI", "BrowserToolPanelWidth", browserToolPanelWidth); + keyFile.set_integer ("GUI", "BrowserToolPanelHeight", browserToolPanelHeight); + keyFile.set_boolean ("GUI", "BrowserToolPanelOpened", browserToolPanelOpened); + keyFile.set_boolean ("GUI", "EditorFilmStripOpened", editorFilmStripOpened); + keyFile.set_boolean ("GUI", "BrowserDirPanelOpened", browserDirPanelOpened); + keyFile.set_integer ("GUI", "HistoryPanelWidth", historyPanelWidth); + keyFile.set_integer ("GUI", "LastPreviewScale", lastScale); + keyFile.set_integer ("GUI", "PanAccelFactor", panAccelFactor); + keyFile.set_boolean ("GUI", "RememberZoomAndPan", rememberZoomAndPan); + keyFile.set_integer ("GUI", "LastCropSize", lastCropSize); + keyFile.set_boolean ("GUI", "ShowHistory", showHistory); + keyFile.set_integer ("GUI", "ShowFilePanelState", showFilePanelState); + keyFile.set_boolean ("GUI", "ShowInfo", showInfo); + keyFile.set_boolean ("GUI", "MainNBVertical", mainNBVertical); + keyFile.set_boolean ("GUI", "ShowClippedHighlights", showClippedHighlights); + keyFile.set_boolean ("GUI", "ShowClippedShadows", showClippedShadows); + keyFile.set_integer ("GUI", "FrameColor", bgcolor); + keyFile.set_boolean ("GUI", "ProcessingQueueEnbled", procQueueEnabled); + Glib::ArrayHandle tpopen = tpOpen; + keyFile.set_integer_list ("GUI", "ToolPanelsExpanded", tpopen); + keyFile.set_integer ("GUI", "MultiDisplayMode", multiDisplayMode); + keyFile.set_double_list ("GUI", "CutOverlayBrush", cutOverlayBrush); + keyFile.set_double_list ("GUI", "NavGuideBrush", navGuideBrush); + keyFile.set_integer ("GUI", "HistogramPosition", histogramPosition); + keyFile.set_boolean ("GUI", "HistogramBar", histogramBar); + keyFile.set_boolean ("GUI", "HistogramFullMode", histogramFullMode); + keyFile.set_boolean ("GUI", "ShowFilmStripToolBar", showFilmStripToolBar); + keyFile.set_boolean ("GUI", "FileBrowserToolbarSingleRow", FileBrowserToolbarSingleRow); + keyFile.set_boolean ("GUI", "HideTPVScrollbar", hideTPVScrollbar); + keyFile.set_boolean ("GUI", "UseIconNoText", UseIconNoText); + keyFile.set_boolean ("GUI", "HistogramWorking", rtSettings.HistogramWorking); + keyFile.set_integer ("GUI", "CurveBBoxPosition", curvebboxpos); + + //Glib::ArrayHandle crvopen = crvOpen; + //keyFile.set_integer_list ("GUI", "CurvePanelsExpanded", crvopen); + + keyFile.set_integer ("Crop Settings", "PPI", cropPPI); + + keyFile.set_string ("Color Management", "ICCDirectory", rtSettings.iccDirectory); + keyFile.set_string ("Color Management", "MonitorProfile", rtSettings.monitorProfile); + keyFile.set_boolean ("Color Management", "AutoMonitorProfile", rtSettings.autoMonitorProfile); + keyFile.set_boolean ("Color Management", "Autocielab", rtSettings.autocielab); + keyFile.set_boolean ("Color Management", "RGBcurvesLumamode_Gamut", rtSettings.rgbcurveslumamode_gamut); + keyFile.set_integer ("Color Management", "Intent", rtSettings.colorimetricIntent); + keyFile.set_integer ("Color Management", "view", rtSettings.viewingdevice); + keyFile.set_integer ("Color Management", "grey", rtSettings.viewingdevicegrey); + keyFile.set_integer ("Color Management", "greySc", rtSettings.viewinggreySc); + + keyFile.set_string ("Color Management", "AdobeRGB", rtSettings.adobe); + keyFile.set_string ("Color Management", "ProPhoto", rtSettings.prophoto); + keyFile.set_string ("Color Management", "ProPhoto10", rtSettings.prophoto10); + keyFile.set_string ("Color Management", "WideGamut", rtSettings.widegamut); + keyFile.set_string ("Color Management", "sRGB", rtSettings.srgb); + keyFile.set_string ("Color Management", "sRGB10", rtSettings.srgb10); + keyFile.set_string ("Color Management", "Beta", rtSettings.beta); + keyFile.set_string ("Color Management", "Best", rtSettings.best); + keyFile.set_string ("Color Management", "Bruce", rtSettings.bruce); + keyFile.set_integer ("Color Management", "WhiteBalanceSpotSize", whiteBalanceSpotSize); + keyFile.set_boolean ("Color Management", "GamutICC", rtSettings.gamutICC); + // keyFile.set_boolean ("Color Management", "BWcomplement", rtSettings.bw_complementary); + keyFile.set_boolean ("Color Management", "Ciecamfloat", rtSettings.ciecamfloat); + keyFile.set_boolean ("Color Management", "GamutLch", rtSettings.gamutLch); + keyFile.set_integer ("Color Management", "ProtectRed", rtSettings.protectred); + keyFile.set_integer ("Color Management", "Amountchroma", rtSettings.amchroma); + keyFile.set_double ("Color Management", "ProtectRedH", rtSettings.protectredh); + keyFile.set_integer ("Color Management", "CRI", rtSettings.CRI_color); + keyFile.set_integer ("Color Management", "DenoiseLabgamma", rtSettings.denoiselabgamma); +// keyFile.set_boolean ("Color Management", "Ciebadpixgauss", rtSettings.ciebadpixgauss); + keyFile.set_double ("Color Management", "CBDLArtif", rtSettings.artifact_cbdl); + keyFile.set_double ("Color Management", "CBDLlevel0", rtSettings.level0_cbdl); + keyFile.set_double ("Color Management", "CBDLlevel123", rtSettings.level123_cbdl); + // keyFile.set_double ("Color Management", "Colortoningab", rtSettings.colortoningab); +// keyFile.set_double ("Color Management", "Decaction", rtSettings.decaction); + keyFile.set_string ("Color Management", "ClutsDirectory", clutsDir); + + + Glib::ArrayHandle bab = baBehav; + keyFile.set_integer_list ("Batch Processing", "AdjusterBehavior", bab); + + keyFile.set_boolean ("Sounds", "Enable", sndEnable); + keyFile.set_string ("Sounds", "BatchQueueDone", sndBatchQueueDone); + keyFile.set_string ("Sounds", "LngEditProcDone", sndLngEditProcDone); + keyFile.set_double ("Sounds", "LngEditProcDoneSecs", sndLngEditProcDoneSecs); + + + keyFile.set_boolean ("Fast Export", "fastexport_bypass_sharpening" , fastexport_bypass_sharpening ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_sharpenEdge" , fastexport_bypass_sharpenEdge ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_sharpenMicro" , fastexport_bypass_sharpenMicro ); + //keyFile.set_boolean ("Fast Export", "fastexport_bypass_lumaDenoise" , fastexport_bypass_lumaDenoise ); + //keyFile.set_boolean ("Fast Export", "fastexport_bypass_colorDenoise" , fastexport_bypass_colorDenoise ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_defringe" , fastexport_bypass_defringe ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_dirpyrDenoise" , fastexport_bypass_dirpyrDenoise ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_sh_hq" , fastexport_bypass_sh_hq ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_dirpyrequalizer" , fastexport_bypass_dirpyrequalizer ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_wavelet" , fastexport_bypass_wavelet ); + keyFile.set_string ("Fast Export", "fastexport_raw_bayer_method" , fastexport_raw_bayer_method ); + //keyFile.set_boolean ("Fast Export", "fastexport_bypass_bayer_raw_all_enhance" , fastexport_bypass_raw_bayer_all_enhance ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_dcb_iterations" , fastexport_bypass_raw_bayer_dcb_iterations ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_dcb_enhance" , fastexport_bypass_raw_bayer_dcb_enhance ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_lmmse_iterations", fastexport_bypass_raw_bayer_lmmse_iterations); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_linenoise" , fastexport_bypass_raw_bayer_linenoise ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_greenthresh" , fastexport_bypass_raw_bayer_greenthresh ); + keyFile.set_string ("Fast Export", "fastexport_raw_xtrans_method" , fastexport_raw_xtrans_method ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_ccSteps" , fastexport_bypass_raw_ccSteps ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_ca" , fastexport_bypass_raw_ca ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_df" , fastexport_bypass_raw_df ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_ff" , fastexport_bypass_raw_ff ); + keyFile.set_string ("Fast Export", "fastexport_icm_input" , fastexport_icm_input ); + keyFile.set_string ("Fast Export", "fastexport_icm_working" , fastexport_icm_working ); + keyFile.set_string ("Fast Export", "fastexport_icm_output" , fastexport_icm_output ); + keyFile.set_string ("Fast Export", "fastexport_icm_gamma" , fastexport_icm_gamma ); + keyFile.set_boolean ("Fast Export", "fastexport_resize_enabled" , fastexport_resize_enabled ); + keyFile.set_double ("Fast Export", "fastexport_resize_scale" , fastexport_resize_scale ); + keyFile.set_string ("Fast Export", "fastexport_resize_appliesTo" , fastexport_resize_appliesTo ); + keyFile.set_string ("Fast Export", "fastexport_resize_method" , fastexport_resize_method ); + keyFile.set_integer ("Fast Export", "fastexport_resize_dataspec" , fastexport_resize_dataspec ); + keyFile.set_integer ("Fast Export", "fastexport_resize_width" , fastexport_resize_width ); + keyFile.set_integer ("Fast Export", "fastexport_resize_height" , fastexport_resize_height ); + + keyFile.set_string ("Dialogs", "LastIccDir", lastIccDir); + keyFile.set_string ("Dialogs", "LastDarkframeDir", lastDarkframeDir); + keyFile.set_string ("Dialogs", "LastFlatfieldDir", lastFlatfieldDir); + keyFile.set_string ("Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir); + keyFile.set_string ("Dialogs", "LastLabCurvesDir", lastLabCurvesDir); + keyFile.set_string ("Dialogs", "LastDenoiseCurvesDir", lastDenoiseCurvesDir); + keyFile.set_string ("Dialogs", "LastWaveletCurvesDir", lastWaveletCurvesDir); + keyFile.set_string ("Dialogs", "LastPFCurvesDir", lastPFCurvesDir); + keyFile.set_string ("Dialogs", "LastHsvCurvesDir", lastHsvCurvesDir); + keyFile.set_string ("Dialogs", "LastBWCurvesDir", lastBWCurvesDir); + keyFile.set_string ("Dialogs", "LastToneCurvesDir", lastToneCurvesDir); + keyFile.set_string ("Dialogs", "LastVibranceCurvesDir", lastVibranceCurvesDir); + keyFile.set_string ("Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir); + + FILE *f = safe_g_fopen (fname, "wt"); + if (f==NULL) { + if (options.rtSettings.verbose) + printf("Options::saveToFile / Error: unable to open file \"%s\" with write access!\n", fname.c_str()); + return 1; + } + else { + fprintf (f, "%s", keyFile.to_data().c_str()); + fclose (f); + return 0; + } +} + +bool Options::load () { + + // Find the application data path + + const gchar* path; + Glib::ustring dPath; + + path = g_getenv("RT_SETTINGS"); + if (path != NULL) { + rtdir = Glib::ustring(path); + if (!Glib::path_is_absolute(rtdir)) + return false; + } + else { + #ifdef WIN32 + WCHAR pathW[MAX_PATH]={0}; char pathA[MAX_PATH]; + + if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_LOCAL_APPDATA,false)) { + WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0); + rtdir = Glib::build_filename(Glib::ustring(pathA), Glib::ustring(CACHEFOLDERNAME)); + } + #else + rtdir = Glib::build_filename(Glib::ustring(g_get_user_config_dir ()), Glib::ustring(CACHEFOLDERNAME)); + #endif + } + + if (options.rtSettings.verbose) + printf("Settings directory (rtdir) = %s\n", rtdir.c_str()); + + // Set the cache folder in RT's base folder + cacheBaseDir = Glib::build_filename(argv0, "cache"); + + // Read the global option file (the one located in the application's base folder) + options.readFromFile (Glib::build_filename(argv0, "options")); + + // Modify the path of the cache folder to the one provided in RT_CACHE environment variable + path = g_getenv("RT_CACHE"); + if (path != NULL) { + cacheBaseDir = Glib::ustring(path); + if (!Glib::path_is_absolute(cacheBaseDir)) + return false; + } + // No environment variable provided, so falling back to the multi user mode, is enabled + else if (options.multiUser) { + #ifdef WIN32 + cacheBaseDir = Glib::build_filename(rtdir, "cache"); + #else + cacheBaseDir = Glib::build_filename(Glib::ustring(g_get_user_cache_dir()), Glib::ustring(CACHEFOLDERNAME)); + #endif + } + + // Check if RT is installed in Multi-User mode + if (options.multiUser) { + // Read the user option file (the one located somewhere in the user's home folder) + // Those values supersets those of the global option file + int r = options.readFromFile (Glib::build_filename(rtdir, "options")); + // If the local option file does not exist or is broken, and the local cache folder does not exist, recreate it + if (r && !safe_g_mkdir_with_parents (rtdir, 511)) { + // Save the option file + options.saveToFile (Glib::build_filename(rtdir, "options")); + } + +#ifdef __APPLE__ + // make sure .local/share exists on OS X so we don't get problems with recently-used.xbel + safe_g_mkdir_with_parents (g_get_user_data_dir(), 511); +#endif + } + + if (options.rtSettings.verbose) + printf("Cache directory (cacheBaseDir) = %s\n", cacheBaseDir.c_str()); + + // Update profile's path and recreate it if necessary + options.updatePaths(); + + // Check default Raw and Img procparams existence + if (options.defProfRaw.empty()) + options.defProfRaw = DEFPROFILE_INTERNAL; + else { + Glib::ustring tmpFName = options.findProfilePath(options.defProfRaw); + if (!tmpFName.empty()) { + if (options.rtSettings.verbose) printf("Raws' default profile \"%s\" found\n", options.defProfRaw.c_str()); + } + else { + if (options.rtSettings.verbose) printf("Raws' default profile \"%s\" not found or not set -> using Internal values\n", options.defProfRaw.c_str()); + options.defProfRaw = DEFPROFILE_INTERNAL; + options.defProfRawMissing = true; + } + } + + if (options.defProfImg.empty()) + options.defProfImg = DEFPROFILE_INTERNAL; + else { + Glib::ustring tmpFName = options.findProfilePath(options.defProfImg); + if (!tmpFName.empty()) { + if (options.rtSettings.verbose) printf("Images' default profile \"%s\" found\n", options.defProfImg.c_str()); + } + else { + if (options.rtSettings.verbose) printf("Images' default profile \"%s\" not found or not set -> using Internal values\n", options.defProfImg.c_str()); + options.defProfImg = DEFPROFILE_INTERNAL; + options.defProfImgMissing = true; + } + } + + //We handle languages using a hierarchy of translations. The top of the hierarchy is default. This includes a default translation for all items + // (most likely using simple English). The next level is the language: for instance, English, French, Chinese, etc. This file should contain a + // generic translation for all items which differ from default. Finally there is the locale. This is region-specific items which differ from the + // language file. These files must be name in the format (), where Language is the name of the language which it inherits from, + // and LC is the local code. Some examples of this would be English (US) (American English), French (FR) (Franch French), French (CA) (Canadian + // French), etc. + // + // Each level will only contain the differences between itself and its parent translation. For instance, English (UK) or English (CA) may + // include the translation "HISTORY_MSG_34;Avoid Colour Clipping" where English would translate it as "HISTORY_MSG_34;Avoid Color Clipping" (note + // the difference in the spelling of 'colour'). + // + // It is important that when naming the translation files, that you stick to the format or (). We depend on that to figure + // out which are the parent translations. Furthermore, there must be a file for each locale () -- you cannot have + // 'French (CA)' unless there is a file 'French'. + + Glib::ustring defaultTranslation = argv0 + "/languages/default"; + Glib::ustring languageTranslation = ""; + Glib::ustring localeTranslation = ""; + + if (options.languageAutoDetect) options.language=langMgr.getOSUserLanguage(); + + if (!options.language.empty()){ + std::vector langPortions = Glib::Regex::split_simple(" ", options.language); + if (langPortions.size() >= 1){ + languageTranslation = argv0 + "/languages/" + langPortions.at(0); + } + if (langPortions.size() >= 2){ + localeTranslation = argv0 + "/languages/" + options.language; + } + } + + langMgr.load(localeTranslation, new MultiLangMgr(languageTranslation, new MultiLangMgr(defaultTranslation))); + + rtengine::init (&options.rtSettings, argv0, rtdir); + + return true; +} + +void Options::save () { + + if (options.multiUser==false) { + options.saveToFile (Glib::build_filename(argv0, "options")); + } + else { + options.saveToFile (Glib::build_filename(rtdir, "options")); + } +} + +/* + * return true if fname ends with one of the retained image file extensions + */ +bool Options::has_retained_extention (Glib::ustring fname) { + + Glib::ustring ext = getExtension(fname).lowercase(); + + if (!ext.empty()) { + // there is an extension to the filename + + // look out if it has one of the retained extensions + for (unsigned int i=0; i=(int)parseExtensionsEnabled.size() || parseExtensionsEnabled[j]; + return false; +} diff --git a/rtgui/options.h b/rtgui/options.h index cde759862..804deeb73 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -1,323 +1,323 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _OPTIONS_ -#define _OPTIONS_ - -#include -#include "../rtengine/rtengine.h" - -#define STARTUPDIR_CURRENT 0 -#define STARTUPDIR_HOME 1 -#define STARTUPDIR_CUSTOM 2 -#define STARTUPDIR_LAST 3 - -// Default bundled profile name to use for Raw images -#ifdef WIN32 -#define DEFPROFILE_RAW "${G}\\Default" -#else -#define DEFPROFILE_RAW "${G}/Default" -#endif -// Default bundled profile name to use for Standard images -#define DEFPROFILE_IMG "Neutral" -// Profile name to use for internal values' profile -#define DEFPROFILE_INTERNAL "Neutral" - -class SaveFormat { - - public: - Glib::ustring format; - int pngBits; - int pngCompression; - int jpegQuality; - int jpegSubSamp; // 1=best compression, 3=best quality - int tiffBits; - bool tiffUncompressed; - bool saveParams; - SaveFormat () : format("jpg"), pngBits(8), pngCompression(6), jpegQuality(90), jpegSubSamp(2), tiffBits(8), tiffUncompressed(true), saveParams(true) {}; -}; - -enum ThFileType {FT_Invalid=-1, FT_None=0, FT_Raw=1, FT_Jpeg=2, FT_Tiff=3, FT_Png=4, FT_Custom=5, FT_Tiff16=6, FT_Png16=7, FT_Custom16=8}; -enum PPLoadLocation {PLL_Cache=0, PLL_Input=1}; -enum CPBKeyType {CPBKT_TID=0, CPBKT_NAME=1, CPBKT_TID_NAME=2}; -enum prevdemo_t {PD_Sidecar=1, PD_Fast=0}; - -namespace rtengine { - class SafeKeyFile; -} - -class Options { - - private: - bool defProfRawMissing; - bool defProfImgMissing; - Glib::ustring userProfilePath; - Glib::ustring globalProfilePath; - bool checkProfilePath(Glib::ustring &path); - bool checkDirPath(Glib::ustring &path, Glib::ustring errString); - void updatePaths(); - int getString (const char* src, char* dst); - void error (int line); - /** - * Safely reads a directory from the configuration file and only applies it - * to the provided destination variable if there is a non-empty string in - * the configuration. - * - * @param keyFile file to read configuration from - * @param section name of the section in the configuration file - * @param entryName name of the entry in the configuration file - * @param destination destination variable to store to - * @return @c true if @p destination was changed - */ - bool safeDirGet(const rtengine::SafeKeyFile& keyFile, const Glib::ustring& section, - const Glib::ustring& entryName, Glib::ustring& destination); - - public: - bool savesParamsAtExit; - SaveFormat saveFormat,saveFormatBatch; - Glib::ustring savePathTemplate; - Glib::ustring savePathFolder; - bool saveUsePathTemplate; - Glib::ustring defProfRaw; - Glib::ustring defProfImg; - Glib::ustring dateFormat; - int adjusterDelay; - int startupDir; - Gtk::SortType dirBrowserSortType; - Glib::ustring startupPath; - Glib::ustring profilePath; // can be an absolute or relative path; depending on this value, bundled profiles may not be found - bool useBundledProfiles; // only used if multiUser == true - Glib::ustring loadSaveProfilePath; - Glib::ustring lastSaveAsPath; - int saveAsDialogWidth; - int saveAsDialogHeight; - int toolPanelWidth; - int browserToolPanelWidth; - int browserToolPanelHeight; - bool browserToolPanelOpened; - bool browserDirPanelOpened; - bool editorFilmStripOpened; - int historyPanelWidth; - Glib::ustring font; - int windowWidth; - int windowHeight; - int windowX; - int windowY; - bool windowMaximized; - int detailWindowWidth; - int detailWindowHeight; - int dirBrowserWidth; - int dirBrowserHeight; - int preferencesWidth; - int preferencesHeight; - int lastScale; - int panAccelFactor; - int lastCropSize; - bool fbOnlyRaw; - bool fbShowDateTime; - bool fbShowBasicExif; - bool fbShowExpComp; - bool fbShowHidden; - int fbArrangement; - bool multiUser; - static Glib::ustring rtdir; - Glib::ustring version; - int thumbSize,thumbSizeTab, thumbSizeQueue; - bool sameThumbSize; // Will use only one thumb size for the file browser and the single editor tab, and avoid recomputing them - bool showHistory; - int showFilePanelState; // 0: normal, 1: maximized, 2: normal, 3: hidden - bool showInfo; - bool mainNBVertical; // main notebook vertical tabs? - int cropPPI; - bool showClippedHighlights; - bool showClippedShadows; - int highlightThreshold; - int shadowThreshold; - bool blinkClipped; - int bgcolor; - Glib::ustring language; - bool languageAutoDetect; - Glib::ustring theme; - bool slimUI; - bool useSystemTheme; - static Glib::ustring cacheBaseDir; - bool autoSuffix; - bool forceFormatOpts; - int saveMethodNum; - bool saveParamsFile; - bool saveParamsCache; - PPLoadLocation paramsLoadLocation; - bool procQueueEnabled; - Glib::ustring gimpDir; - Glib::ustring psDir; - Glib::ustring customEditorProg; - Glib::ustring CPBPath; // Custom Profile Builder's path - CPBKeyType CPBKeys; // Custom Profile Builder's key type - int editorToSendTo; - int maxThumbnailHeight; - std::size_t maxCacheEntries; - ThFileType thumbnailFormat; - int thumbInterp; // 0: nearest, 1: bilinear - bool liveThumbnails; - std::vector parseExtensions; // List containing all extensions type - std::vector parseExtensionsEnabled; // List of bool to retain extension or not - std::vector parsedExtensions; // List containing all retained extensions (lowercase) - std::vector tpOpen; - //std::vector crvOpen; - std::vector baBehav; - rtengine::Settings rtSettings; - - std::vector favoriteDirs; - std::vector renameTemplates; - bool renameUseTemplates; - bool internalThumbIfUntouched; - bool overwriteOutputFile; - - std::vector thumbnailZoomRatios; - bool overlayedFileNames; - bool filmStripOverlayedFileNames; - bool showFileNames; - bool filmStripShowFileNames; - bool tabbedUI; - int previewSizeTab,previewSizeBrowser; - bool rememberZoomAndPan; - int multiDisplayMode; // 0=none, 1=Edit panels on other display - std::vector cutOverlayBrush; // Red;Green;Blue;Alpha , all ranging 0..1 - std::vector navGuideBrush; // Red;Green;Blue;Alpha , all ranging 0..1 - - Glib::ustring sndBatchQueueDone; - Glib::ustring sndLngEditProcDone; - double sndLngEditProcDoneSecs; // Minimum processing time seconds till the sound is played - bool sndEnable; - - bool tunnelMetaData; // Pass through IPTC and XMP unchanged - int histogramPosition; // 0=disabled, 1=left pane, 2=right pane - //int histogramWorking; // 0=disabled, 1=left pane, 2=right pane - bool histogramBar; - bool histogramFullMode; - bool showProfileSelector; - bool FileBrowserToolbarSingleRow; - bool hideTPVScrollbar; - bool UseIconNoText; - int whiteBalanceSpotSize; - int curvebboxpos; // 0=above, 1=right, 2=below, 3=left - - bool showFilmStripToolBar; - - // Performance options - Glib::ustring clutsDir; - int rgbDenoiseThreadLimit; // maximum number of threads for the denoising tool ; 0 = use the maximum available - int maxInspectorBuffers; // maximum number of buffers (i.e. images) for the Inspector feature - int clutCacheSize; - bool filledProfile; // Used as reminder for the ProfilePanel "mode" +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _OPTIONS_ +#define _OPTIONS_ + +#include +#include "../rtengine/rtengine.h" + +#define STARTUPDIR_CURRENT 0 +#define STARTUPDIR_HOME 1 +#define STARTUPDIR_CUSTOM 2 +#define STARTUPDIR_LAST 3 + +// Default bundled profile name to use for Raw images +#ifdef WIN32 +#define DEFPROFILE_RAW "${G}\\Default" +#else +#define DEFPROFILE_RAW "${G}/Default" +#endif +// Default bundled profile name to use for Standard images +#define DEFPROFILE_IMG "Neutral" +// Profile name to use for internal values' profile +#define DEFPROFILE_INTERNAL "Neutral" + +class SaveFormat { + + public: + Glib::ustring format; + int pngBits; + int pngCompression; + int jpegQuality; + int jpegSubSamp; // 1=best compression, 3=best quality + int tiffBits; + bool tiffUncompressed; + bool saveParams; + SaveFormat () : format("jpg"), pngBits(8), pngCompression(6), jpegQuality(90), jpegSubSamp(2), tiffBits(8), tiffUncompressed(true), saveParams(true) {}; +}; + +enum ThFileType {FT_Invalid=-1, FT_None=0, FT_Raw=1, FT_Jpeg=2, FT_Tiff=3, FT_Png=4, FT_Custom=5, FT_Tiff16=6, FT_Png16=7, FT_Custom16=8}; +enum PPLoadLocation {PLL_Cache=0, PLL_Input=1}; +enum CPBKeyType {CPBKT_TID=0, CPBKT_NAME=1, CPBKT_TID_NAME=2}; +enum prevdemo_t {PD_Sidecar=1, PD_Fast=0}; + +namespace rtengine { + class SafeKeyFile; +} + +class Options { + + private: + bool defProfRawMissing; + bool defProfImgMissing; + Glib::ustring userProfilePath; + Glib::ustring globalProfilePath; + bool checkProfilePath(Glib::ustring &path); + bool checkDirPath(Glib::ustring &path, Glib::ustring errString); + void updatePaths(); + int getString (const char* src, char* dst); + void error (int line); + /** + * Safely reads a directory from the configuration file and only applies it + * to the provided destination variable if there is a non-empty string in + * the configuration. + * + * @param keyFile file to read configuration from + * @param section name of the section in the configuration file + * @param entryName name of the entry in the configuration file + * @param destination destination variable to store to + * @return @c true if @p destination was changed + */ + bool safeDirGet(const rtengine::SafeKeyFile& keyFile, const Glib::ustring& section, + const Glib::ustring& entryName, Glib::ustring& destination); + + public: + bool savesParamsAtExit; + SaveFormat saveFormat,saveFormatBatch; + Glib::ustring savePathTemplate; + Glib::ustring savePathFolder; + bool saveUsePathTemplate; + Glib::ustring defProfRaw; + Glib::ustring defProfImg; + Glib::ustring dateFormat; + int adjusterDelay; + int startupDir; + Gtk::SortType dirBrowserSortType; + Glib::ustring startupPath; + Glib::ustring profilePath; // can be an absolute or relative path; depending on this value, bundled profiles may not be found + bool useBundledProfiles; // only used if multiUser == true + Glib::ustring loadSaveProfilePath; + Glib::ustring lastSaveAsPath; + int saveAsDialogWidth; + int saveAsDialogHeight; + int toolPanelWidth; + int browserToolPanelWidth; + int browserToolPanelHeight; + bool browserToolPanelOpened; + bool browserDirPanelOpened; + bool editorFilmStripOpened; + int historyPanelWidth; + Glib::ustring font; + int windowWidth; + int windowHeight; + int windowX; + int windowY; + bool windowMaximized; + int detailWindowWidth; + int detailWindowHeight; + int dirBrowserWidth; + int dirBrowserHeight; + int preferencesWidth; + int preferencesHeight; + int lastScale; + int panAccelFactor; + int lastCropSize; + bool fbOnlyRaw; + bool fbShowDateTime; + bool fbShowBasicExif; + bool fbShowExpComp; + bool fbShowHidden; + int fbArrangement; + bool multiUser; + static Glib::ustring rtdir; + Glib::ustring version; + int thumbSize,thumbSizeTab, thumbSizeQueue; + bool sameThumbSize; // Will use only one thumb size for the file browser and the single editor tab, and avoid recomputing them + bool showHistory; + int showFilePanelState; // 0: normal, 1: maximized, 2: normal, 3: hidden + bool showInfo; + bool mainNBVertical; // main notebook vertical tabs? + int cropPPI; + bool showClippedHighlights; + bool showClippedShadows; + int highlightThreshold; + int shadowThreshold; + bool blinkClipped; + int bgcolor; + Glib::ustring language; + bool languageAutoDetect; + Glib::ustring theme; + bool slimUI; + bool useSystemTheme; + static Glib::ustring cacheBaseDir; + bool autoSuffix; + bool forceFormatOpts; + int saveMethodNum; + bool saveParamsFile; + bool saveParamsCache; + PPLoadLocation paramsLoadLocation; + bool procQueueEnabled; + Glib::ustring gimpDir; + Glib::ustring psDir; + Glib::ustring customEditorProg; + Glib::ustring CPBPath; // Custom Profile Builder's path + CPBKeyType CPBKeys; // Custom Profile Builder's key type + int editorToSendTo; + int maxThumbnailHeight; + std::size_t maxCacheEntries; + ThFileType thumbnailFormat; + int thumbInterp; // 0: nearest, 1: bilinear + bool liveThumbnails; + std::vector parseExtensions; // List containing all extensions type + std::vector parseExtensionsEnabled; // List of bool to retain extension or not + std::vector parsedExtensions; // List containing all retained extensions (lowercase) + std::vector tpOpen; + //std::vector crvOpen; + std::vector baBehav; + rtengine::Settings rtSettings; + + std::vector favoriteDirs; + std::vector renameTemplates; + bool renameUseTemplates; + bool internalThumbIfUntouched; + bool overwriteOutputFile; + + std::vector thumbnailZoomRatios; + bool overlayedFileNames; + bool filmStripOverlayedFileNames; + bool showFileNames; + bool filmStripShowFileNames; + bool tabbedUI; + int previewSizeTab,previewSizeBrowser; + bool rememberZoomAndPan; + int multiDisplayMode; // 0=none, 1=Edit panels on other display + std::vector cutOverlayBrush; // Red;Green;Blue;Alpha , all ranging 0..1 + std::vector navGuideBrush; // Red;Green;Blue;Alpha , all ranging 0..1 + + Glib::ustring sndBatchQueueDone; + Glib::ustring sndLngEditProcDone; + double sndLngEditProcDoneSecs; // Minimum processing time seconds till the sound is played + bool sndEnable; + + bool tunnelMetaData; // Pass through IPTC and XMP unchanged + int histogramPosition; // 0=disabled, 1=left pane, 2=right pane + //int histogramWorking; // 0=disabled, 1=left pane, 2=right pane + bool histogramBar; + bool histogramFullMode; + bool showProfileSelector; + bool FileBrowserToolbarSingleRow; + bool hideTPVScrollbar; + bool UseIconNoText; + int whiteBalanceSpotSize; + int curvebboxpos; // 0=above, 1=right, 2=below, 3=left + + bool showFilmStripToolBar; + + // Performance options + Glib::ustring clutsDir; + int rgbDenoiseThreadLimit; // maximum number of threads for the denoising tool ; 0 = use the maximum available + int maxInspectorBuffers; // maximum number of buffers (i.e. images) for the Inspector feature + int clutCacheSize; + bool filledProfile; // Used as reminder for the ProfilePanel "mode" prevdemo_t prevdemo; // Demosaicing method used for the <100% preview - bool serializeTiffRead; - - bool menuGroupRank; - bool menuGroupLabel; - bool menuGroupFileOperations; - bool menuGroupProfileOperations; - bool menuGroupExtProg; - - // fast export options - bool fastexport_bypass_sharpening; - bool fastexport_bypass_sharpenEdge; - bool fastexport_bypass_sharpenMicro; - //bool fastexport_bypass_lumaDenoise; - //bool fastexport_bypass_colorDenoise; - bool fastexport_bypass_defringe; - bool fastexport_bypass_dirpyrDenoise; - bool fastexport_bypass_sh_hq; - bool fastexport_bypass_dirpyrequalizer; - bool fastexport_bypass_wavelet; - Glib::ustring fastexport_raw_bayer_method; - //bool fastexport_bypass_raw_bayer_all_enhance; - bool fastexport_bypass_raw_bayer_dcb_iterations; - bool fastexport_bypass_raw_bayer_dcb_enhance; - bool fastexport_bypass_raw_bayer_lmmse_iterations; - bool fastexport_bypass_raw_bayer_linenoise; - bool fastexport_bypass_raw_bayer_greenthresh; - Glib::ustring fastexport_raw_xtrans_method; - bool fastexport_bypass_raw_ccSteps; - bool fastexport_bypass_raw_ca; - bool fastexport_bypass_raw_df; - bool fastexport_bypass_raw_ff; - Glib::ustring fastexport_icm_input; - Glib::ustring fastexport_icm_working; - Glib::ustring fastexport_icm_output; - Glib::ustring fastexport_icm_gamma; - bool fastexport_resize_enabled; - double fastexport_resize_scale; - Glib::ustring fastexport_resize_appliesTo; - Glib::ustring fastexport_resize_method; - int fastexport_resize_dataspec; - int fastexport_resize_width; - int fastexport_resize_height; - - // Dialog settings - Glib::ustring lastIccDir; - Glib::ustring lastDarkframeDir; - Glib::ustring lastFlatfieldDir; - Glib::ustring lastRgbCurvesDir; - Glib::ustring lastLabCurvesDir; - Glib::ustring lastDenoiseCurvesDir; - Glib::ustring lastWaveletCurvesDir; - Glib::ustring lastPFCurvesDir; - Glib::ustring lastHsvCurvesDir; - Glib::ustring lastToneCurvesDir; - Glib::ustring lastColorToningCurvesDir; - Glib::ustring lastVibranceCurvesDir; - Glib::ustring lastProfilingReferenceDir; + bool serializeTiffRead; + + bool menuGroupRank; + bool menuGroupLabel; + bool menuGroupFileOperations; + bool menuGroupProfileOperations; + bool menuGroupExtProg; + + // fast export options + bool fastexport_bypass_sharpening; + bool fastexport_bypass_sharpenEdge; + bool fastexport_bypass_sharpenMicro; + //bool fastexport_bypass_lumaDenoise; + //bool fastexport_bypass_colorDenoise; + bool fastexport_bypass_defringe; + bool fastexport_bypass_dirpyrDenoise; + bool fastexport_bypass_sh_hq; + bool fastexport_bypass_dirpyrequalizer; + bool fastexport_bypass_wavelet; + Glib::ustring fastexport_raw_bayer_method; + //bool fastexport_bypass_raw_bayer_all_enhance; + bool fastexport_bypass_raw_bayer_dcb_iterations; + bool fastexport_bypass_raw_bayer_dcb_enhance; + bool fastexport_bypass_raw_bayer_lmmse_iterations; + bool fastexport_bypass_raw_bayer_linenoise; + bool fastexport_bypass_raw_bayer_greenthresh; + Glib::ustring fastexport_raw_xtrans_method; + bool fastexport_bypass_raw_ccSteps; + bool fastexport_bypass_raw_ca; + bool fastexport_bypass_raw_df; + bool fastexport_bypass_raw_ff; + Glib::ustring fastexport_icm_input; + Glib::ustring fastexport_icm_working; + Glib::ustring fastexport_icm_output; + Glib::ustring fastexport_icm_gamma; + bool fastexport_resize_enabled; + double fastexport_resize_scale; + Glib::ustring fastexport_resize_appliesTo; + Glib::ustring fastexport_resize_method; + int fastexport_resize_dataspec; + int fastexport_resize_width; + int fastexport_resize_height; + + // Dialog settings + Glib::ustring lastIccDir; + Glib::ustring lastDarkframeDir; + Glib::ustring lastFlatfieldDir; + Glib::ustring lastRgbCurvesDir; + Glib::ustring lastLabCurvesDir; + Glib::ustring lastDenoiseCurvesDir; + Glib::ustring lastWaveletCurvesDir; + Glib::ustring lastPFCurvesDir; + Glib::ustring lastHsvCurvesDir; + Glib::ustring lastToneCurvesDir; + Glib::ustring lastColorToningCurvesDir; + Glib::ustring lastVibranceCurvesDir; + Glib::ustring lastProfilingReferenceDir; Glib::ustring lastBWCurvesDir; size_t maxRecentFolders; // max. number of recent folders stored in options file - std::vector recentFolders; // List containing all recent folders - - - Options (); - - Options* copyFrom (Options* other); - void filterOutParsedExtensions (); - void setDefaults (); - int readFromFile (Glib::ustring fname); - int saveToFile (Glib::ustring fname); - static bool load (); - static void save (); - - // if multiUser=false, send back the global profile path - Glib::ustring getPreferredProfilePath(); - Glib::ustring getUserProfilePath() { return userProfilePath; } - Glib::ustring getGlobalProfilePath() { return globalProfilePath; } - Glib::ustring findProfilePath(Glib::ustring &profName); - bool has_retained_extention (Glib::ustring fname); - bool is_extention_enabled(Glib::ustring ext); - bool is_defProfRawMissing() { return defProfRawMissing; } - bool is_defProfImgMissing() { return defProfImgMissing; } - void setDefProfRawMissing(bool value) { defProfRawMissing = value; } - void setDefProfImgMissing(bool value) { defProfImgMissing = value; } -}; - -extern Options options; -extern Glib::ustring argv0; -extern Glib::ustring argv1; -extern bool simpleEditor; -extern Glib::ustring versionString; -extern Glib::ustring versionSuffixString; -extern Glib::ustring paramFileExtension; - -#endif + std::vector recentFolders; // List containing all recent folders + + + Options (); + + Options* copyFrom (Options* other); + void filterOutParsedExtensions (); + void setDefaults (); + int readFromFile (Glib::ustring fname); + int saveToFile (Glib::ustring fname); + static bool load (); + static void save (); + + // if multiUser=false, send back the global profile path + Glib::ustring getPreferredProfilePath(); + Glib::ustring getUserProfilePath() { return userProfilePath; } + Glib::ustring getGlobalProfilePath() { return globalProfilePath; } + Glib::ustring findProfilePath(Glib::ustring &profName); + bool has_retained_extention (Glib::ustring fname); + bool is_extention_enabled(Glib::ustring ext); + bool is_defProfRawMissing() { return defProfRawMissing; } + bool is_defProfImgMissing() { return defProfImgMissing; } + void setDefProfRawMissing(bool value) { defProfRawMissing = value; } + void setDefProfImgMissing(bool value) { defProfImgMissing = value; } +}; + +extern Options options; +extern Glib::ustring argv0; +extern Glib::ustring argv1; +extern bool simpleEditor; +extern Glib::ustring versionString; +extern Glib::ustring versionSuffixString; +extern Glib::ustring paramFileExtension; + +#endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 0ebadd3c9..0359726a1 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -1,1395 +1,1395 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "paramsedited.h" -#include -#include "options.h" -#include "addsetids.h" - -ParamsEdited::ParamsEdited (bool value) { - - set (value); -} - -void ParamsEdited::set (bool v) { - - general.rank = v; - general.colorlabel = v; - general.intrash = v; - toneCurve.curve = v; - toneCurve.curve2 = v; - toneCurve.curveMode = v; - toneCurve.curveMode2 = v; - toneCurve.brightness = v; - toneCurve.black = v; - toneCurve.contrast = v; - toneCurve.saturation = v; - toneCurve.shcompr = v; - toneCurve.hlcompr = v; - toneCurve.hlcomprthresh = v; - toneCurve.autoexp = v; - toneCurve.clip = v; - toneCurve.expcomp = v; - toneCurve.hrenabled = v; - toneCurve.method = v; - labCurve.lcurve = v; - labCurve.acurve = v; - labCurve.bcurve = v; - labCurve.cccurve = v; - labCurve.chcurve = v; - labCurve.lhcurve = v; - labCurve.hhcurve = v; - labCurve.lccurve = v; - labCurve.clcurve = v; - labCurve.brightness = v; - labCurve.contrast = v; - labCurve.chromaticity = v; - labCurve.avoidcolorshift = v; - labCurve.rstprotection = v; - labCurve.lcredsk = v; - rgbCurves.lumamode = v; - rgbCurves.rcurve = v; - rgbCurves.gcurve = v; - rgbCurves.bcurve = v; - colorToning.enabled = v; - colorToning.autosat = v; - colorToning.opacityCurve = v; - colorToning.colorCurve = v; - colorToning.satprotectionthreshold = v; - colorToning.saturatedopacity = v; - colorToning.strength = v; - colorToning.shadowsColSat = v; - colorToning.hlColSat = v; - colorToning.balance = v; - colorToning.clcurve = v; - colorToning.method = v; - colorToning.twocolor = v; - colorToning.cl2curve = v; - colorToning.redlow = v; - colorToning.greenlow = v; - colorToning.bluelow = v; - colorToning.satlow = v; - colorToning.sathigh = v; - colorToning.redmed = v; - colorToning.greenmed = v; - colorToning.bluemed = v; - colorToning.redhigh = v; - colorToning.greenhigh = v; - colorToning.bluehigh = v; - colorToning.lumamode = v; - - sharpening.enabled = v; - sharpening.radius = v; - sharpening.amount = v; - sharpening.threshold = v; - sharpening.edgesonly = v; - sharpening.edges_radius = v; - sharpening.edges_tolerance = v; - sharpening.halocontrol = v; - sharpening.halocontrol_amount = v; - sharpening.method = v; - sharpening.deconvamount = v; - sharpening.deconvradius = v; - sharpening.deconviter = v; - sharpening.deconvdamping = v; - prsharpening.enabled = v; - prsharpening.radius = v; - prsharpening.amount = v; - prsharpening.threshold = v; - prsharpening.edgesonly = v; - prsharpening.edges_radius = v; - prsharpening.edges_tolerance = v; - prsharpening.halocontrol = v; - prsharpening.halocontrol_amount = v; - prsharpening.method = v; - prsharpening.deconvamount = v; - prsharpening.deconvradius = v; - prsharpening.deconviter = v; - prsharpening.deconvdamping = v; - sharpenEdge.enabled = v; - sharpenEdge.passes = v; - sharpenEdge.amount = v; - sharpenEdge.threechannels = v; - sharpenMicro.enabled = v; - sharpenMicro.matrix = v; - sharpenMicro.amount = v; - sharpenMicro.uniformity = v; - vibrance.enabled = v; - vibrance.pastels = v; - vibrance.saturated = v; - vibrance.psthreshold = v; - vibrance.protectskins = v; - vibrance.avoidcolorshift = v; - vibrance.pastsattog = v; - vibrance.skintonescurve = v; - colorappearance.enabled = v; - colorappearance.degree = v; - colorappearance.autodegree = v; - colorappearance.surround = v; - colorappearance.adapscen = v; - colorappearance.autoadapscen = v; - colorappearance.adaplum = v; - colorappearance.badpixsl = v; - colorappearance.wbmodel = v; - colorappearance.algo = v; - - colorappearance.jlight = v; - colorappearance.qbright = v; - colorappearance.chroma = v; - colorappearance.schroma = v; - colorappearance.mchroma = v; - colorappearance.contrast = v; - colorappearance.qcontrast = v; - colorappearance.colorh = v; - colorappearance.rstprotection = v; - colorappearance.surrsource = v; - colorappearance.gamut = v; -// colorappearance.badpix = v; - colorappearance.datacie = v; - colorappearance.tonecie = v; -// colorappearance.sharpcie = v; - colorappearance.curve = v; - colorappearance.curve2 = v; - colorappearance.curve3 = v; - colorappearance.curveMode = v; - colorappearance.curveMode2 = v; - colorappearance.curveMode3 = v; - - //colorBoost.amount = v; - //colorBoost.avoidclip = v; - //colorBoost.enable_saturationlimiter = v; - //colorBoost.saturationlimit = v; - wb.method = v; - wb.green = v; - wb.temperature = v; - wb.equal = v; - //colorShift.a = v; - //colorShift.b = v; - //lumaDenoise.enabled = v; - //lumaDenoise.radius = v; - //lumaDenoise.edgetolerance = v; - //colorDenoise.enabled = v; - //colorDenoise.amount = v; - defringe.enabled = v; - defringe.radius = v; - defringe.threshold = v; - defringe.huecurve = v; - impulseDenoise.enabled = v; - impulseDenoise.thresh = v; - dirpyrDenoise.enabled = v; - dirpyrDenoise.enhance = v; -// dirpyrDenoise.perform = v; - dirpyrDenoise.lcurve = v; - dirpyrDenoise.cccurve = v; - dirpyrDenoise.median = v; - dirpyrDenoise.autochroma = v; - dirpyrDenoise.luma = v; - dirpyrDenoise.Ldetail = v; - dirpyrDenoise.chroma = v; - dirpyrDenoise.redchro = v; - dirpyrDenoise.bluechro = v; - dirpyrDenoise.gamma = v; - dirpyrDenoise.passes = v; - dirpyrDenoise.dmethod = v; - dirpyrDenoise.Lmethod = v; - dirpyrDenoise.Cmethod = v; - dirpyrDenoise.C2method = v; - dirpyrDenoise.smethod = v; - dirpyrDenoise.medmethod = v; - dirpyrDenoise.methodmed = v; - dirpyrDenoise.rgbmethod = v; - epd.enabled = v; - epd.strength = v; - epd.gamma = v; - epd.edgeStopping = v; - epd.scale = v; - epd.reweightingIterates = v; - sh.enabled = v; - sh.hq = v; - sh.highlights = v; - sh.htonalwidth = v; - sh.shadows = v; - sh.stonalwidth = v; - sh.localcontrast = v; - sh.radius = v; - crop.enabled = v; - crop.x = v; - crop.y = v; - crop.w = v; - crop.h = v; - crop.fixratio = v; - crop.ratio = v; - crop.orientation = v; - crop.guide = v; - coarse.rotate = v; - coarse.hflip = v; - coarse.vflip = v; - commonTrans.autofill = v; - rotate.degree = v; - distortion.amount = v; - lensProf.lcpFile = v; - lensProf.useDist = v; - lensProf.useVign = v; - lensProf.useCA = v; - perspective.horizontal = v; - perspective.vertical = v; - gradient.enabled = v; - gradient.degree = v; - gradient.feather = v; - gradient.strength = v; - gradient.centerX = v; - gradient.centerY = v; - pcvignette.enabled = v; - pcvignette.strength = v; - pcvignette.feather = v; - pcvignette.roundness = v; - cacorrection.red = v; - cacorrection.blue = v; - vignetting.amount = v; - vignetting.radius = v; - vignetting.strength = v; - vignetting.centerX = v; - vignetting.centerY = v; - chmixer.red[0] = v; - chmixer.red[1] = v; - chmixer.red[2] = v; - chmixer.green[0] = v; - chmixer.green[1] = v; - chmixer.green[2] = v; - chmixer.blue[0] = v; - chmixer.blue[1] = v; - chmixer.blue[2] = v; - blackwhite.enabled = v; - blackwhite.enabledcc = v; - blackwhite.mixerRed = v; - blackwhite.mixerOrange = v; - blackwhite.mixerYellow = v; - blackwhite.mixerGreen = v; - blackwhite.mixerCyan = v; - blackwhite.mixerBlue = v; - blackwhite.mixerMagenta = v; - blackwhite.mixerPurple = v; - blackwhite.gammaRed = v; - blackwhite.gammaGreen = v; - blackwhite.gammaBlue = v; - blackwhite.filter = v; - blackwhite.setting = v; - blackwhite.method = v; - blackwhite.luminanceCurve = v; - blackwhite.beforeCurve = v; - blackwhite.beforeCurveMode = v; - blackwhite.afterCurve = v; - blackwhite.afterCurveMode = v; - blackwhite.autoc = v; - blackwhite.algo = v; - - - resize.scale = v; - resize.appliesTo = v; - resize.method = v; - resize.dataspec = v; - resize.width = v; - resize.height = v; - resize.enabled = v; - icm.input = v; - icm.toneCurve = v; - icm.applyLookTable = v; - icm.applyBaselineExposureOffset = v; - icm.applyHueSatMap = v; - icm.blendCMSMatrix = v; - icm.dcpIlluminant = v; - icm.working = v; - icm.output = v; - icm.gamma = v; - icm.freegamma = v; - icm.gampos = v; - icm.slpos = v; - raw.bayersensor.method = v; - raw.bayersensor.ccSteps = v; - raw.bayersensor.exBlack0 = v; - raw.bayersensor.exBlack1 = v; - raw.bayersensor.exBlack2 = v; - raw.bayersensor.exBlack3 = v; - raw.bayersensor.exTwoGreen=v; - raw.bayersensor.dcbIterations = v; - raw.bayersensor.dcbEnhance = v; - //raw.bayersensor.allEnhance = v; - raw.bayersensor.lmmseIterations = v; - raw.bayersensor.greenEq = v; - raw.bayersensor.linenoise = v; - raw.xtranssensor.method = v; - raw.xtranssensor.ccSteps = v; - raw.xtranssensor.exBlackRed= v; - raw.xtranssensor.exBlackGreen = v; - raw.xtranssensor.exBlackBlue = v; - raw.caCorrection = v; - raw.caBlue = v; - raw.caRed = v; - raw.hotPixelFilter = v; - raw.deadPixelFilter = v; - raw.hotDeadPixelThresh = v; - raw.darkFrame = v; - raw.dfAuto = v; - raw.ff_file = v; - raw.ff_AutoSelect = v; - raw.ff_BlurRadius = v; - raw.ff_BlurType = v; - raw.ff_AutoClipControl = v; - raw.ff_clipControl = v; - raw.exPos = v; - raw.exPreser = v; - wavelet.enabled = v; - wavelet.strength = v; - wavelet.balance = v; - wavelet.iter = v; - wavelet.median = v; - wavelet.medianlev = v; - wavelet.linkedg = v; - wavelet.cbenab = v; - wavelet.greenhigh = v; - wavelet.greenmed = v; - wavelet.greenlow = v; - wavelet.bluehigh = v; - wavelet.bluemed = v; - wavelet.bluelow = v; - wavelet.lipst = v; - wavelet.Medgreinf = v; - wavelet.avoid = v; - wavelet.tmr = v; - wavelet.Lmethod = v; - wavelet.CLmethod = v; - wavelet.Backmethod = v; - wavelet.Tilesmethod = v; - wavelet.daubcoeffmethod = v; - wavelet.CHmethod = v; - wavelet.CHSLmethod = v; - wavelet.EDmethod = v; - wavelet.NPmethod = v; - wavelet.BAmethod = v; - wavelet.TMmethod = v; - wavelet.HSmethod = v; - wavelet.Dirmethod = v; - wavelet.rescon = v; - wavelet.resconH = v; - wavelet.reschro = v; - wavelet.tmrs = v; - wavelet.gamma = v; - wavelet.sup = v; - wavelet.sky = v; - wavelet.thres = v; - wavelet.threshold = v; - wavelet.threshold2 = v; - wavelet.edgedetect = v; - wavelet.edgedetectthr = v; - wavelet.edgedetectthr2 = v; - wavelet.edgesensi = v; - wavelet.edgeampli = v; - wavelet.chroma = v; - wavelet.chro = v; - wavelet.contrast = v; - wavelet.edgrad = v; - wavelet.edgval = v; - wavelet.edgthresh = v; - wavelet.thr = v; - wavelet.thrH = v; - wavelet.skinprotect = v; - wavelet.hueskin = v; - wavelet.hueskin2 = v; - wavelet.hllev = v; - wavelet.bllev = v; - wavelet.edgcont = v; - wavelet.level0noise = v; - wavelet.level1noise = v; - wavelet.level2noise = v; - wavelet.level3noise = v; - wavelet.ccwcurve = v; - wavelet.opacityCurveRG = v; - wavelet.opacityCurveBY = v; - wavelet.opacityCurveW = v; - wavelet.opacityCurveWL = v; - wavelet.hhcurve = v; - wavelet.Chcurve = v; - wavelet.wavclCurve = v; - - wavelet.pastlev = v; - wavelet.satlev = v; -// wavelet.enacont = v; -// wavelet.enachrom = v; -// wavelet.enaedge = v; -// wavelet.enares = v; - wavelet.expfinal = v; - wavelet.expcontrast = v; - wavelet.expchroma = v; - wavelet.expedge = v; - wavelet.expresid = v; - wavelet.exptoning = v; - wavelet.expnoise = v; - - for(int i = 0; i < 9; i++) { - wavelet.c[i] = v; - } - for(int i = 0; i < 9; i++) { - wavelet.ch[i] = v; - } - - dirpyrequalizer.enabled = v; - dirpyrequalizer.gamutlab = v; - for(int i = 0; i < 6; i++) { - dirpyrequalizer.mult[i] = v; - } - dirpyrequalizer.threshold = v; - dirpyrequalizer.skinprotect = v; - dirpyrequalizer.hueskin = v; - //dirpyrequalizer.algo = v; - hsvequalizer.hcurve = v; - hsvequalizer.scurve = v; - hsvequalizer.vcurve = v; - filmSimulation.enabled = v; - filmSimulation.clutFilename = v; - filmSimulation.strength = v; - - exif = v; - iptc = v; -} - -using namespace rtengine; -using namespace rtengine::procparams; - -void ParamsEdited::initFrom (const std::vector& src) { - - set (true); - if (src.empty()) - return; - - const ProcParams& p = src[0]; - for (size_t i=1; ifirst] = i->second; - } - - // IPTC changes are added to the existing ones - if (iptc) - for (procparams::IPTCPairs::const_iterator i=mods.iptc.begin(); i!=mods.iptc.end(); i++) { - toEdit.iptc[i->first] = i->second; - } -} - -bool RAWParamsEdited::BayerSensor::isUnchanged() const { - return method && ccSteps && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq - && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; -} - -bool RAWParamsEdited::XTransSensor::isUnchanged() const { - return method && ccSteps && exBlackRed && exBlackGreen && exBlackBlue; -} - -bool RAWParamsEdited::isUnchanged() const { - return bayersensor.isUnchanged() && xtranssensor.isUnchanged() && caCorrection && caRed && caBlue && hotPixelFilter && deadPixelFilter && hotDeadPixelThresh && darkFrame - && dfAuto && ff_file && ff_AutoSelect && ff_BlurRadius && ff_BlurType && exPos && exPreser && ff_AutoClipControl && ff_clipControl; -} - -bool LensProfParamsEdited::isUnchanged() const { - return lcpFile; -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "paramsedited.h" +#include +#include "options.h" +#include "addsetids.h" + +ParamsEdited::ParamsEdited (bool value) { + + set (value); +} + +void ParamsEdited::set (bool v) { + + general.rank = v; + general.colorlabel = v; + general.intrash = v; + toneCurve.curve = v; + toneCurve.curve2 = v; + toneCurve.curveMode = v; + toneCurve.curveMode2 = v; + toneCurve.brightness = v; + toneCurve.black = v; + toneCurve.contrast = v; + toneCurve.saturation = v; + toneCurve.shcompr = v; + toneCurve.hlcompr = v; + toneCurve.hlcomprthresh = v; + toneCurve.autoexp = v; + toneCurve.clip = v; + toneCurve.expcomp = v; + toneCurve.hrenabled = v; + toneCurve.method = v; + labCurve.lcurve = v; + labCurve.acurve = v; + labCurve.bcurve = v; + labCurve.cccurve = v; + labCurve.chcurve = v; + labCurve.lhcurve = v; + labCurve.hhcurve = v; + labCurve.lccurve = v; + labCurve.clcurve = v; + labCurve.brightness = v; + labCurve.contrast = v; + labCurve.chromaticity = v; + labCurve.avoidcolorshift = v; + labCurve.rstprotection = v; + labCurve.lcredsk = v; + rgbCurves.lumamode = v; + rgbCurves.rcurve = v; + rgbCurves.gcurve = v; + rgbCurves.bcurve = v; + colorToning.enabled = v; + colorToning.autosat = v; + colorToning.opacityCurve = v; + colorToning.colorCurve = v; + colorToning.satprotectionthreshold = v; + colorToning.saturatedopacity = v; + colorToning.strength = v; + colorToning.shadowsColSat = v; + colorToning.hlColSat = v; + colorToning.balance = v; + colorToning.clcurve = v; + colorToning.method = v; + colorToning.twocolor = v; + colorToning.cl2curve = v; + colorToning.redlow = v; + colorToning.greenlow = v; + colorToning.bluelow = v; + colorToning.satlow = v; + colorToning.sathigh = v; + colorToning.redmed = v; + colorToning.greenmed = v; + colorToning.bluemed = v; + colorToning.redhigh = v; + colorToning.greenhigh = v; + colorToning.bluehigh = v; + colorToning.lumamode = v; + + sharpening.enabled = v; + sharpening.radius = v; + sharpening.amount = v; + sharpening.threshold = v; + sharpening.edgesonly = v; + sharpening.edges_radius = v; + sharpening.edges_tolerance = v; + sharpening.halocontrol = v; + sharpening.halocontrol_amount = v; + sharpening.method = v; + sharpening.deconvamount = v; + sharpening.deconvradius = v; + sharpening.deconviter = v; + sharpening.deconvdamping = v; + prsharpening.enabled = v; + prsharpening.radius = v; + prsharpening.amount = v; + prsharpening.threshold = v; + prsharpening.edgesonly = v; + prsharpening.edges_radius = v; + prsharpening.edges_tolerance = v; + prsharpening.halocontrol = v; + prsharpening.halocontrol_amount = v; + prsharpening.method = v; + prsharpening.deconvamount = v; + prsharpening.deconvradius = v; + prsharpening.deconviter = v; + prsharpening.deconvdamping = v; + sharpenEdge.enabled = v; + sharpenEdge.passes = v; + sharpenEdge.amount = v; + sharpenEdge.threechannels = v; + sharpenMicro.enabled = v; + sharpenMicro.matrix = v; + sharpenMicro.amount = v; + sharpenMicro.uniformity = v; + vibrance.enabled = v; + vibrance.pastels = v; + vibrance.saturated = v; + vibrance.psthreshold = v; + vibrance.protectskins = v; + vibrance.avoidcolorshift = v; + vibrance.pastsattog = v; + vibrance.skintonescurve = v; + colorappearance.enabled = v; + colorappearance.degree = v; + colorappearance.autodegree = v; + colorappearance.surround = v; + colorappearance.adapscen = v; + colorappearance.autoadapscen = v; + colorappearance.adaplum = v; + colorappearance.badpixsl = v; + colorappearance.wbmodel = v; + colorappearance.algo = v; + + colorappearance.jlight = v; + colorappearance.qbright = v; + colorappearance.chroma = v; + colorappearance.schroma = v; + colorappearance.mchroma = v; + colorappearance.contrast = v; + colorappearance.qcontrast = v; + colorappearance.colorh = v; + colorappearance.rstprotection = v; + colorappearance.surrsource = v; + colorappearance.gamut = v; +// colorappearance.badpix = v; + colorappearance.datacie = v; + colorappearance.tonecie = v; +// colorappearance.sharpcie = v; + colorappearance.curve = v; + colorappearance.curve2 = v; + colorappearance.curve3 = v; + colorappearance.curveMode = v; + colorappearance.curveMode2 = v; + colorappearance.curveMode3 = v; + + //colorBoost.amount = v; + //colorBoost.avoidclip = v; + //colorBoost.enable_saturationlimiter = v; + //colorBoost.saturationlimit = v; + wb.method = v; + wb.green = v; + wb.temperature = v; + wb.equal = v; + //colorShift.a = v; + //colorShift.b = v; + //lumaDenoise.enabled = v; + //lumaDenoise.radius = v; + //lumaDenoise.edgetolerance = v; + //colorDenoise.enabled = v; + //colorDenoise.amount = v; + defringe.enabled = v; + defringe.radius = v; + defringe.threshold = v; + defringe.huecurve = v; + impulseDenoise.enabled = v; + impulseDenoise.thresh = v; + dirpyrDenoise.enabled = v; + dirpyrDenoise.enhance = v; +// dirpyrDenoise.perform = v; + dirpyrDenoise.lcurve = v; + dirpyrDenoise.cccurve = v; + dirpyrDenoise.median = v; + dirpyrDenoise.autochroma = v; + dirpyrDenoise.luma = v; + dirpyrDenoise.Ldetail = v; + dirpyrDenoise.chroma = v; + dirpyrDenoise.redchro = v; + dirpyrDenoise.bluechro = v; + dirpyrDenoise.gamma = v; + dirpyrDenoise.passes = v; + dirpyrDenoise.dmethod = v; + dirpyrDenoise.Lmethod = v; + dirpyrDenoise.Cmethod = v; + dirpyrDenoise.C2method = v; + dirpyrDenoise.smethod = v; + dirpyrDenoise.medmethod = v; + dirpyrDenoise.methodmed = v; + dirpyrDenoise.rgbmethod = v; + epd.enabled = v; + epd.strength = v; + epd.gamma = v; + epd.edgeStopping = v; + epd.scale = v; + epd.reweightingIterates = v; + sh.enabled = v; + sh.hq = v; + sh.highlights = v; + sh.htonalwidth = v; + sh.shadows = v; + sh.stonalwidth = v; + sh.localcontrast = v; + sh.radius = v; + crop.enabled = v; + crop.x = v; + crop.y = v; + crop.w = v; + crop.h = v; + crop.fixratio = v; + crop.ratio = v; + crop.orientation = v; + crop.guide = v; + coarse.rotate = v; + coarse.hflip = v; + coarse.vflip = v; + commonTrans.autofill = v; + rotate.degree = v; + distortion.amount = v; + lensProf.lcpFile = v; + lensProf.useDist = v; + lensProf.useVign = v; + lensProf.useCA = v; + perspective.horizontal = v; + perspective.vertical = v; + gradient.enabled = v; + gradient.degree = v; + gradient.feather = v; + gradient.strength = v; + gradient.centerX = v; + gradient.centerY = v; + pcvignette.enabled = v; + pcvignette.strength = v; + pcvignette.feather = v; + pcvignette.roundness = v; + cacorrection.red = v; + cacorrection.blue = v; + vignetting.amount = v; + vignetting.radius = v; + vignetting.strength = v; + vignetting.centerX = v; + vignetting.centerY = v; + chmixer.red[0] = v; + chmixer.red[1] = v; + chmixer.red[2] = v; + chmixer.green[0] = v; + chmixer.green[1] = v; + chmixer.green[2] = v; + chmixer.blue[0] = v; + chmixer.blue[1] = v; + chmixer.blue[2] = v; + blackwhite.enabled = v; + blackwhite.enabledcc = v; + blackwhite.mixerRed = v; + blackwhite.mixerOrange = v; + blackwhite.mixerYellow = v; + blackwhite.mixerGreen = v; + blackwhite.mixerCyan = v; + blackwhite.mixerBlue = v; + blackwhite.mixerMagenta = v; + blackwhite.mixerPurple = v; + blackwhite.gammaRed = v; + blackwhite.gammaGreen = v; + blackwhite.gammaBlue = v; + blackwhite.filter = v; + blackwhite.setting = v; + blackwhite.method = v; + blackwhite.luminanceCurve = v; + blackwhite.beforeCurve = v; + blackwhite.beforeCurveMode = v; + blackwhite.afterCurve = v; + blackwhite.afterCurveMode = v; + blackwhite.autoc = v; + blackwhite.algo = v; + + + resize.scale = v; + resize.appliesTo = v; + resize.method = v; + resize.dataspec = v; + resize.width = v; + resize.height = v; + resize.enabled = v; + icm.input = v; + icm.toneCurve = v; + icm.applyLookTable = v; + icm.applyBaselineExposureOffset = v; + icm.applyHueSatMap = v; + icm.blendCMSMatrix = v; + icm.dcpIlluminant = v; + icm.working = v; + icm.output = v; + icm.gamma = v; + icm.freegamma = v; + icm.gampos = v; + icm.slpos = v; + raw.bayersensor.method = v; + raw.bayersensor.ccSteps = v; + raw.bayersensor.exBlack0 = v; + raw.bayersensor.exBlack1 = v; + raw.bayersensor.exBlack2 = v; + raw.bayersensor.exBlack3 = v; + raw.bayersensor.exTwoGreen=v; + raw.bayersensor.dcbIterations = v; + raw.bayersensor.dcbEnhance = v; + //raw.bayersensor.allEnhance = v; + raw.bayersensor.lmmseIterations = v; + raw.bayersensor.greenEq = v; + raw.bayersensor.linenoise = v; + raw.xtranssensor.method = v; + raw.xtranssensor.ccSteps = v; + raw.xtranssensor.exBlackRed= v; + raw.xtranssensor.exBlackGreen = v; + raw.xtranssensor.exBlackBlue = v; + raw.caCorrection = v; + raw.caBlue = v; + raw.caRed = v; + raw.hotPixelFilter = v; + raw.deadPixelFilter = v; + raw.hotDeadPixelThresh = v; + raw.darkFrame = v; + raw.dfAuto = v; + raw.ff_file = v; + raw.ff_AutoSelect = v; + raw.ff_BlurRadius = v; + raw.ff_BlurType = v; + raw.ff_AutoClipControl = v; + raw.ff_clipControl = v; + raw.exPos = v; + raw.exPreser = v; + wavelet.enabled = v; + wavelet.strength = v; + wavelet.balance = v; + wavelet.iter = v; + wavelet.median = v; + wavelet.medianlev = v; + wavelet.linkedg = v; + wavelet.cbenab = v; + wavelet.greenhigh = v; + wavelet.greenmed = v; + wavelet.greenlow = v; + wavelet.bluehigh = v; + wavelet.bluemed = v; + wavelet.bluelow = v; + wavelet.lipst = v; + wavelet.Medgreinf = v; + wavelet.avoid = v; + wavelet.tmr = v; + wavelet.Lmethod = v; + wavelet.CLmethod = v; + wavelet.Backmethod = v; + wavelet.Tilesmethod = v; + wavelet.daubcoeffmethod = v; + wavelet.CHmethod = v; + wavelet.CHSLmethod = v; + wavelet.EDmethod = v; + wavelet.NPmethod = v; + wavelet.BAmethod = v; + wavelet.TMmethod = v; + wavelet.HSmethod = v; + wavelet.Dirmethod = v; + wavelet.rescon = v; + wavelet.resconH = v; + wavelet.reschro = v; + wavelet.tmrs = v; + wavelet.gamma = v; + wavelet.sup = v; + wavelet.sky = v; + wavelet.thres = v; + wavelet.threshold = v; + wavelet.threshold2 = v; + wavelet.edgedetect = v; + wavelet.edgedetectthr = v; + wavelet.edgedetectthr2 = v; + wavelet.edgesensi = v; + wavelet.edgeampli = v; + wavelet.chroma = v; + wavelet.chro = v; + wavelet.contrast = v; + wavelet.edgrad = v; + wavelet.edgval = v; + wavelet.edgthresh = v; + wavelet.thr = v; + wavelet.thrH = v; + wavelet.skinprotect = v; + wavelet.hueskin = v; + wavelet.hueskin2 = v; + wavelet.hllev = v; + wavelet.bllev = v; + wavelet.edgcont = v; + wavelet.level0noise = v; + wavelet.level1noise = v; + wavelet.level2noise = v; + wavelet.level3noise = v; + wavelet.ccwcurve = v; + wavelet.opacityCurveRG = v; + wavelet.opacityCurveBY = v; + wavelet.opacityCurveW = v; + wavelet.opacityCurveWL = v; + wavelet.hhcurve = v; + wavelet.Chcurve = v; + wavelet.wavclCurve = v; + + wavelet.pastlev = v; + wavelet.satlev = v; +// wavelet.enacont = v; +// wavelet.enachrom = v; +// wavelet.enaedge = v; +// wavelet.enares = v; + wavelet.expfinal = v; + wavelet.expcontrast = v; + wavelet.expchroma = v; + wavelet.expedge = v; + wavelet.expresid = v; + wavelet.exptoning = v; + wavelet.expnoise = v; + + for(int i = 0; i < 9; i++) { + wavelet.c[i] = v; + } + for(int i = 0; i < 9; i++) { + wavelet.ch[i] = v; + } + + dirpyrequalizer.enabled = v; + dirpyrequalizer.gamutlab = v; + for(int i = 0; i < 6; i++) { + dirpyrequalizer.mult[i] = v; + } + dirpyrequalizer.threshold = v; + dirpyrequalizer.skinprotect = v; + dirpyrequalizer.hueskin = v; + //dirpyrequalizer.algo = v; + hsvequalizer.hcurve = v; + hsvequalizer.scurve = v; + hsvequalizer.vcurve = v; + filmSimulation.enabled = v; + filmSimulation.clutFilename = v; + filmSimulation.strength = v; + + exif = v; + iptc = v; +} + +using namespace rtengine; +using namespace rtengine::procparams; + +void ParamsEdited::initFrom (const std::vector& src) { + + set (true); + if (src.empty()) + return; + + const ProcParams& p = src[0]; + for (size_t i=1; ifirst] = i->second; + } + + // IPTC changes are added to the existing ones + if (iptc) + for (procparams::IPTCPairs::const_iterator i=mods.iptc.begin(); i!=mods.iptc.end(); i++) { + toEdit.iptc[i->first] = i->second; + } +} + +bool RAWParamsEdited::BayerSensor::isUnchanged() const { + return method && ccSteps && dcbIterations && dcbEnhance && lmmseIterations/*&& allEnhance*/ && greenEq + && linenoise && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; +} + +bool RAWParamsEdited::XTransSensor::isUnchanged() const { + return method && ccSteps && exBlackRed && exBlackGreen && exBlackBlue; +} + +bool RAWParamsEdited::isUnchanged() const { + return bayersensor.isUnchanged() && xtranssensor.isUnchanged() && caCorrection && caRed && caBlue && hotPixelFilter && deadPixelFilter && hotDeadPixelThresh && darkFrame + && dfAuto && ff_file && ff_AutoSelect && ff_BlurRadius && ff_BlurType && exPos && exPreser && ff_AutoClipControl && ff_clipControl; +} + +bool LensProfParamsEdited::isUnchanged() const { + return lcpFile; +} diff --git a/rtgui/placesbrowser.cc b/rtgui/placesbrowser.cc index a2dc33bfe..ba1c27873 100644 --- a/rtgui/placesbrowser.cc +++ b/rtgui/placesbrowser.cc @@ -78,9 +78,9 @@ PlacesBrowser::PlacesBrowser () : listener (NULL) { } // For drive letter comparison -bool compareMountByRoot (Glib::RefPtr a,Glib::RefPtr b) { - return a->get_root()->get_parse_name() < b->get_root()->get_parse_name(); -} +bool compareMountByRoot (Glib::RefPtr a,Glib::RefPtr b) { + return a->get_root()->get_parse_name() < b->get_root()->get_parse_name(); +} void PlacesBrowser::refreshPlacesList () { @@ -118,7 +118,7 @@ void PlacesBrowser::refreshPlacesList () { } catch (Gio::Error&) { /* This will be thrown if the path doesn't exist */ } } - if (!placesModel->children().empty()) { + if (!placesModel->children().empty()) { Gtk::TreeModel::Row newrow = *(placesModel->append()); newrow[placesColumns.rowSeparator] = true; } @@ -127,7 +127,7 @@ void PlacesBrowser::refreshPlacesList () { std::vector > drives = vm->get_connected_drives (); for (size_t j=0; j > volumes = drives[j]->get_volumes (); - if (volumes.empty()) { + if (volumes.empty()) { Gtk::TreeModel::Row newrow = *(placesModel->append()); newrow[placesColumns.label] = drives[j]->get_name (); newrow[placesColumns.icon] = drives[j]->get_icon (); @@ -200,7 +200,7 @@ void PlacesBrowser::refreshPlacesList () { } } // append favorites - if (!placesModel->children().empty()) { + if (!placesModel->children().empty()) { Gtk::TreeModel::Row newrow = *(placesModel->append()); newrow[placesColumns.rowSeparator] = true; } diff --git a/rtgui/popupbutton.cc b/rtgui/popupbutton.cc index 6db2879fd..f3a857bc3 100644 --- a/rtgui/popupbutton.cc +++ b/rtgui/popupbutton.cc @@ -1,39 +1,39 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - * - * Class created by Jean-Christophe FRISCH, aka 'Hombre' - */ - -#include "popupbutton.h" - -/* - * PopUpButton::PopUpButton (const Glib::ustring& label, bool imgRight) - * - * Creates a button with a contextual menu where you can select an item that the button content will reflect - * - * Parameters: - * label = label displayed in the button - */ -PopUpButton::PopUpButton (const Glib::ustring& label) : Gtk::Button(), PopUpCommon(this, label) { } - -void PopUpButton::show() { - PopUpCommon::show(); -} -void PopUpButton::set_tooltip_text (const Glib::ustring &text) { - PopUpCommon::set_tooltip_text (text); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ + +#include "popupbutton.h" + +/* + * PopUpButton::PopUpButton (const Glib::ustring& label, bool imgRight) + * + * Creates a button with a contextual menu where you can select an item that the button content will reflect + * + * Parameters: + * label = label displayed in the button + */ +PopUpButton::PopUpButton (const Glib::ustring& label) : Gtk::Button(), PopUpCommon(this, label) { } + +void PopUpButton::show() { + PopUpCommon::show(); +} +void PopUpButton::set_tooltip_text (const Glib::ustring &text) { + PopUpCommon::set_tooltip_text (text); +} diff --git a/rtgui/popupbutton.h b/rtgui/popupbutton.h index 6239c4a40..9361912e2 100644 --- a/rtgui/popupbutton.h +++ b/rtgui/popupbutton.h @@ -1,35 +1,35 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - * - * Class created by Jean-Christophe FRISCH, aka 'Hombre' - */ -#ifndef _POPUPBUTTON_ -#define _POPUPBUTTON_ - -#include -#include "popupcommon.h" - -class PopUpButton : public Gtk::Button, public PopUpCommon { - -public: - PopUpButton (const Glib::ustring& label = ""); - void show (); - void set_tooltip_text (const Glib::ustring &text); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ +#ifndef _POPUPBUTTON_ +#define _POPUPBUTTON_ + +#include +#include "popupcommon.h" + +class PopUpButton : public Gtk::Button, public PopUpCommon { + +public: + PopUpButton (const Glib::ustring& label = ""); + void show (); + void set_tooltip_text (const Glib::ustring &text); +}; + +#endif diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc index 9c0ee4d66..b639c5b74 100644 --- a/rtgui/popupcommon.cc +++ b/rtgui/popupcommon.cc @@ -1,159 +1,159 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - * - * Class created by Jean-Christophe FRISCH, aka 'Hombre' - */ - -#include "multilangmgr.h" -#include "popupcommon.h" -#include "../rtengine/safegtk.h" -#include "rtimage.h" - -PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) { - button = thisButton; - hasMenu = false; - imageContainer = Gtk::manage( new Gtk::HBox(false, 0)); - button->set_relief (Gtk::RELIEF_NORMAL); - button->set_border_width (0); - button->add(*imageContainer); - if (label.size()) { - Gtk::Label* buttonLabel = Gtk::manage ( new Gtk::Label(label + " ") ); - imageContainer->pack_start(*buttonLabel, Gtk::PACK_SHRINK, 0); - } - // Create the global container and put the button in it - buttonGroup = Gtk::manage( new Gtk::HBox(false, 0)); - buttonGroup->pack_start(*button, Gtk::PACK_EXPAND_WIDGET, 0); - // Create the list entry - imageFilenames.clear(); - images.clear(); - sItems.clear(); - items.clear(); - selected = -1; // -1 : means that the button is invalid - menu = 0; - buttonImage = 0; - buttonHint = ""; -} - -PopUpCommon::~PopUpCommon () { - for (std::vector::iterator i = images.begin(); i != images.end(); ++i) - { - delete *i; - } - for (std::vector::iterator i = items.begin(); i != items.end(); ++i) - { - delete *i; - } - if (menu) delete menu; - if (buttonImage) delete buttonImage; - delete buttonGroup; -} - -PopUpCommon::type_signal_changed PopUpCommon::signal_changed() { - return message; -} - -bool PopUpCommon::addEntry (Glib::ustring fileName, Glib::ustring label) { - bool added = false; - if ( label.size() ) { - imageFilenames.push_back(fileName); - sItems.push_back(label); - // Create the image - RTImage* newImage = new RTImage(fileName); - images.push_back(newImage); - int currPos = (int)images.size(); - // Create the menu item - Gtk::ImageMenuItem* newItem = new Gtk::ImageMenuItem (*newImage, label); - items.push_back(newItem); - if (selected == -1) { - // Create the menu on the first item - menu = new Gtk::Menu (); - // Create the image for the button - buttonImage = new RTImage(fileName); - // Use the first image by default - imageContainer->pack_start(*buttonImage,Gtk::PACK_EXPAND_WIDGET); - selected = 0; - } - // When there is at least 1 choice, we add the arrow button - if (images.size() == 1) { - Gtk::Button* arrowButton = Gtk::manage( new Gtk::Button() ); - RTImage* arrowImage = Gtk::manage( new RTImage("popuparrow.png") ); - arrowButton->add(*arrowImage); //menuSymbol); - arrowButton->set_relief (Gtk::RELIEF_NONE); - arrowButton->set_border_width (0); - buttonGroup->pack_start(*arrowButton,Gtk::PACK_SHRINK, 0); - arrowButton->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) ); - hasMenu = true; - } - newItem->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &PopUpCommon::entrySelected), currPos-1)); - menu->attach (*newItem, 0, 1, currPos-1, currPos); - // The item has been created - added = true; - } - return added; -} - -// TODO: 'PopUpCommon::removeEntry' method to be created... - -void PopUpCommon::entrySelected (int i) { - if (setSelected((unsigned int)i)) - // Emit a a signal if the selected item has changed - message.emit(selected); -} - -/* - * Set the button image with the selected item - */ -bool PopUpCommon::setSelected (int entryNum) { +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ + +#include "multilangmgr.h" +#include "popupcommon.h" +#include "../rtengine/safegtk.h" +#include "rtimage.h" + +PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) { + button = thisButton; + hasMenu = false; + imageContainer = Gtk::manage( new Gtk::HBox(false, 0)); + button->set_relief (Gtk::RELIEF_NORMAL); + button->set_border_width (0); + button->add(*imageContainer); + if (label.size()) { + Gtk::Label* buttonLabel = Gtk::manage ( new Gtk::Label(label + " ") ); + imageContainer->pack_start(*buttonLabel, Gtk::PACK_SHRINK, 0); + } + // Create the global container and put the button in it + buttonGroup = Gtk::manage( new Gtk::HBox(false, 0)); + buttonGroup->pack_start(*button, Gtk::PACK_EXPAND_WIDGET, 0); + // Create the list entry + imageFilenames.clear(); + images.clear(); + sItems.clear(); + items.clear(); + selected = -1; // -1 : means that the button is invalid + menu = 0; + buttonImage = 0; + buttonHint = ""; +} + +PopUpCommon::~PopUpCommon () { + for (std::vector::iterator i = images.begin(); i != images.end(); ++i) + { + delete *i; + } + for (std::vector::iterator i = items.begin(); i != items.end(); ++i) + { + delete *i; + } + if (menu) delete menu; + if (buttonImage) delete buttonImage; + delete buttonGroup; +} + +PopUpCommon::type_signal_changed PopUpCommon::signal_changed() { + return message; +} + +bool PopUpCommon::addEntry (Glib::ustring fileName, Glib::ustring label) { + bool added = false; + if ( label.size() ) { + imageFilenames.push_back(fileName); + sItems.push_back(label); + // Create the image + RTImage* newImage = new RTImage(fileName); + images.push_back(newImage); + int currPos = (int)images.size(); + // Create the menu item + Gtk::ImageMenuItem* newItem = new Gtk::ImageMenuItem (*newImage, label); + items.push_back(newItem); + if (selected == -1) { + // Create the menu on the first item + menu = new Gtk::Menu (); + // Create the image for the button + buttonImage = new RTImage(fileName); + // Use the first image by default + imageContainer->pack_start(*buttonImage,Gtk::PACK_EXPAND_WIDGET); + selected = 0; + } + // When there is at least 1 choice, we add the arrow button + if (images.size() == 1) { + Gtk::Button* arrowButton = Gtk::manage( new Gtk::Button() ); + RTImage* arrowImage = Gtk::manage( new RTImage("popuparrow.png") ); + arrowButton->add(*arrowImage); //menuSymbol); + arrowButton->set_relief (Gtk::RELIEF_NONE); + arrowButton->set_border_width (0); + buttonGroup->pack_start(*arrowButton,Gtk::PACK_SHRINK, 0); + arrowButton->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) ); + hasMenu = true; + } + newItem->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &PopUpCommon::entrySelected), currPos-1)); + menu->attach (*newItem, 0, 1, currPos-1, currPos); + // The item has been created + added = true; + } + return added; +} + +// TODO: 'PopUpCommon::removeEntry' method to be created... + +void PopUpCommon::entrySelected (int i) { + if (setSelected((unsigned int)i)) + // Emit a a signal if the selected item has changed + message.emit(selected); +} + +/* + * Set the button image with the selected item + */ +bool PopUpCommon::setSelected (int entryNum) { if (entryNum < 0 || entryNum > ((int)images.size()-1) || (int)entryNum == selected) - return false; - else { - // Maybe we could do something better than loading the image file each time the selection is changed !? - buttonImage->changeImage(imageFilenames.at(entryNum)); - selected = entryNum; - setButtonHint(); - return true; - } -} - -void PopUpCommon::show() { - menu->reposition(); - setButtonHint(); - menu->show_all(); - buttonGroup->show_all(); -} - -void PopUpCommon::setButtonHint() { - Glib::ustring hint; - if (!buttonHint.empty()) { - hint = buttonHint; - if (selected > -1) - hint += " "; - } - if (selected > -1) - hint += sItems.at(selected); - button->set_tooltip_markup(hint); -} - -void PopUpCommon::showMenu(GdkEventButton* event) { - if (event->button == 1) menu->popup(event->button, event->time); -} - -void PopUpCommon::set_tooltip_text (const Glib::ustring &text) { - buttonHint = text; - setButtonHint(); -} + return false; + else { + // Maybe we could do something better than loading the image file each time the selection is changed !? + buttonImage->changeImage(imageFilenames.at(entryNum)); + selected = entryNum; + setButtonHint(); + return true; + } +} + +void PopUpCommon::show() { + menu->reposition(); + setButtonHint(); + menu->show_all(); + buttonGroup->show_all(); +} + +void PopUpCommon::setButtonHint() { + Glib::ustring hint; + if (!buttonHint.empty()) { + hint = buttonHint; + if (selected > -1) + hint += " "; + } + if (selected > -1) + hint += sItems.at(selected); + button->set_tooltip_markup(hint); +} + +void PopUpCommon::showMenu(GdkEventButton* event) { + if (event->button == 1) menu->popup(event->button, event->time); +} + +void PopUpCommon::set_tooltip_text (const Glib::ustring &text) { + buttonHint = text; + setButtonHint(); +} diff --git a/rtgui/popupcommon.h b/rtgui/popupcommon.h index eba9e1ea3..5bdeedbf0 100644 --- a/rtgui/popupcommon.h +++ b/rtgui/popupcommon.h @@ -1,70 +1,70 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - * - * Class created by Jean-Christophe FRISCH, aka 'Hombre' - */ -#ifndef _POPUPCOMMON_ -#define _POPUPCOMMON_ - - -#include -#include -#include "rtimage.h" - - -class PopUpCommon { - -public: - typedef sigc::signal type_signal_changed; - type_signal_changed signal_changed(); - Gtk::HBox* buttonGroup; // this is the widget to be packed - - PopUpCommon (Gtk::Button* button, const Glib::ustring& label = ""); - virtual ~PopUpCommon (); - bool addEntry (Glib::ustring fileName, Glib::ustring label); - bool setSelected (int entryNum); - int getSelected () { return selected; } - void setButtonHint(); - void show (); - void set_tooltip_text (const Glib::ustring &text); - -private: - type_signal_changed message; - - /* - TODO: MenuItem::get_label() doesn't return any string, or an empty string !? - That's why we store entries strings in sItems, but it would be nice to get ride of it... - */ - std::vector sItems; - std::vector imageFilenames; - std::vector images; - std::vector items; - Glib::ustring buttonHint; - RTImage* buttonImage; - Gtk::HBox* imageContainer; - Gtk::Menu* menu; - Gtk::Button* button; - int selected; - bool hasMenu; - - void showMenu(GdkEventButton* event); - void entrySelected (int i); - -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ +#ifndef _POPUPCOMMON_ +#define _POPUPCOMMON_ + + +#include +#include +#include "rtimage.h" + + +class PopUpCommon { + +public: + typedef sigc::signal type_signal_changed; + type_signal_changed signal_changed(); + Gtk::HBox* buttonGroup; // this is the widget to be packed + + PopUpCommon (Gtk::Button* button, const Glib::ustring& label = ""); + virtual ~PopUpCommon (); + bool addEntry (Glib::ustring fileName, Glib::ustring label); + bool setSelected (int entryNum); + int getSelected () { return selected; } + void setButtonHint(); + void show (); + void set_tooltip_text (const Glib::ustring &text); + +private: + type_signal_changed message; + + /* + TODO: MenuItem::get_label() doesn't return any string, or an empty string !? + That's why we store entries strings in sItems, but it would be nice to get ride of it... + */ + std::vector sItems; + std::vector imageFilenames; + std::vector images; + std::vector items; + Glib::ustring buttonHint; + RTImage* buttonImage; + Gtk::HBox* imageContainer; + Gtk::Menu* menu; + Gtk::Button* button; + int selected; + bool hasMenu; + + void showMenu(GdkEventButton* event); + void entrySelected (int i); + +}; + +#endif diff --git a/rtgui/popuptogglebutton.cc b/rtgui/popuptogglebutton.cc index 7bdf9ef51..1ede81795 100644 --- a/rtgui/popuptogglebutton.cc +++ b/rtgui/popuptogglebutton.cc @@ -1,39 +1,39 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - * - * Class created by Jean-Christophe FRISCH, aka 'Hombre' - */ - -#include "popuptogglebutton.h" - -/* - * PopUpToggleButton::PopUpToggleButton (const Glib::ustring& label, bool imgRight) - * - * Creates a toggle button with a contextual menu where you can select an item that the button content will reflect - * - * Parameters: - * label = label displayed in the button - */ -PopUpToggleButton::PopUpToggleButton (const Glib::ustring& label) : Gtk::ToggleButton(), PopUpCommon(this, label) { } - -void PopUpToggleButton::show() { - PopUpCommon::show(); -} -void PopUpToggleButton::set_tooltip_text (const Glib::ustring &text) { - PopUpCommon::set_tooltip_text (text); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ + +#include "popuptogglebutton.h" + +/* + * PopUpToggleButton::PopUpToggleButton (const Glib::ustring& label, bool imgRight) + * + * Creates a toggle button with a contextual menu where you can select an item that the button content will reflect + * + * Parameters: + * label = label displayed in the button + */ +PopUpToggleButton::PopUpToggleButton (const Glib::ustring& label) : Gtk::ToggleButton(), PopUpCommon(this, label) { } + +void PopUpToggleButton::show() { + PopUpCommon::show(); +} +void PopUpToggleButton::set_tooltip_text (const Glib::ustring &text) { + PopUpCommon::set_tooltip_text (text); +} diff --git a/rtgui/popuptogglebutton.h b/rtgui/popuptogglebutton.h index 762c88926..c6ee5ab05 100644 --- a/rtgui/popuptogglebutton.h +++ b/rtgui/popuptogglebutton.h @@ -1,35 +1,35 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - * - * Class created by Jean-Christophe FRISCH, aka 'Hombre' - */ -#ifndef _POPUPTOGGLEBUTTON_ -#define _POPUPTOGGLEBUTTON_ - -#include "popupbutton.h" -#include "popupcommon.h" - -class PopUpToggleButton : public Gtk::ToggleButton, public PopUpCommon { - -public: - PopUpToggleButton (const Glib::ustring& label = ""); - void show (); - void set_tooltip_text (const Glib::ustring &text); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * Class created by Jean-Christophe FRISCH, aka 'Hombre' + */ +#ifndef _POPUPTOGGLEBUTTON_ +#define _POPUPTOGGLEBUTTON_ + +#include "popupbutton.h" +#include "popupcommon.h" + +class PopUpToggleButton : public Gtk::ToggleButton, public PopUpCommon { + +public: + PopUpToggleButton (const Glib::ustring& label = ""); + void show (); + void set_tooltip_text (const Glib::ustring &text); +}; + +#endif diff --git a/rtgui/ppversion.h b/rtgui/ppversion.h index 76b4fb53f..6a695416e 100644 --- a/rtgui/ppversion.h +++ b/rtgui/ppversion.h @@ -1,47 +1,47 @@ -#ifndef _PPVERSION_ -#define _PPVERSION_ - -// This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes -#define PPVERSION 326 -#define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified - -/* - Log of version changes - 326 2015-07-26 - [Exposure] Added 'Perceptual' tone curve mode +#ifndef _PPVERSION_ +#define _PPVERSION_ + +// This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes +#define PPVERSION 326 +#define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified + +/* + Log of version changes + 326 2015-07-26 + [Exposure] Added 'Perceptual' tone curve mode 325 2015-07-23 [Exposure] [RGB Curves] [B&W] Normalized RGB pipeline curve gammas to sRGB (before it was a mix between sRGB and 1.0 and depended on file format) - 323 2015-10-05 - [Exposure] Added 'Luminance' tone curve mode - 322 2015-01-31 + 323 2015-10-05 + [Exposure] Added 'Luminance' tone curve mode + 322 2015-01-31 [Wavelet] new tool using wavelet levels - 321 2014-08-17 - [Film Simulation] new tool using HALDCLUT files + 321 2014-08-17 + [Film Simulation] new tool using HALDCLUT files 320 2014-07-02 (yes, same version number... this is an error due to a wrong version number set in comment of previous change) New [RAW Bayer] and [RAW X-Trans] sections, with some parameters transfered from [RAW] to [RAW Bayer] - 320 2014-03-29 - [ColorToning] new tool for color toning - 319 2014-02-11 + 320 2014-03-29 + [ColorToning] new tool for color toning + 319 2014-02-11 Hue skin for Contrast by detail levels 318 2014-02-10 Vignetting Correction bug makes hard transitions for positive Amount values, Issue 2241 317 2014-01-19 - changes to behaviour of LC curve, Issue 2209 - 315 2013-12-12 - add LH et HH curve to lab mode - 313 2013-11-19 - add CL curve to lab mode - 312 2013-11-08 - added numerous changes to [channel mixer] - 311 2013-11-07 - [Gradient] new tool (gradient/graduated filter - [PCVignette] new tool (vignette filter) - 310 2013-09-16 - Defringing /Threshold - changed calculation, issue 1801 - 307 2013-03-16 - [Perspective] Horizontal and Vertical changed from int to double - added [Directional Pyramid Denoising] Method, Redchro, Bluechro - added [RGB Curves] LumaMode - */ - -#endif + changes to behaviour of LC curve, Issue 2209 + 315 2013-12-12 + add LH et HH curve to lab mode + 313 2013-11-19 + add CL curve to lab mode + 312 2013-11-08 + added numerous changes to [channel mixer] + 311 2013-11-07 + [Gradient] new tool (gradient/graduated filter + [PCVignette] new tool (vignette filter) + 310 2013-09-16 + Defringing /Threshold - changed calculation, issue 1801 + 307 2013-03-16 + [Perspective] Horizontal and Vertical changed from int to double + added [Directional Pyramid Denoising] Method, Redchro, Bluechro + added [RGB Curves] LumaMode + */ + +#endif diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 26ba14c35..15cfb8afa 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -1,2048 +1,2048 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath , Oliver Duis - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include -#include "preferences.h" -#include "multilangmgr.h" -#include "splash.h" -#include "cachemanager.h" -#include "addsetids.h" -#include "../rtengine/dfmanager.h" -#include "../rtengine/ffmanager.h" -#include -#include "../rtengine/safegtk.h" -#include "rtimage.h" -#ifdef _OPENMP -#include -#endif - -extern Options options; -extern Glib::ustring argv0; - -Preferences::Preferences (RTWindow *rtwindow) : rprofiles(NULL), iprofiles(NULL), parent(rtwindow) { - - splash = NULL; - - set_title (M("MAIN_BUTTON_PREFERENCES")); - - moptions.copyFrom (&options); - oldSlimUI = options.slimUI; - - /* - * Do not increase height, since it's not visible on e.g. smaller netbook screens - * Default height is about 620 pixels actually, that's why we do not set the height anymore - * Netbook users will most certainly set a smaller font and use the "slimUI" mode, - * so they'll be able to shrink the pref window and close it. - */ - set_size_request (650, -1); - set_default_size (options.preferencesWidth, options.preferencesHeight); - set_border_width(4); - - Gtk::VBox* mainvb = get_vbox (); - mainvb->set_spacing(8); - set_has_separator (false); - - Gtk::Notebook* nb = Gtk::manage (new Gtk::Notebook ()); - mainvb->pack_start (*nb); - - Gtk::HBox* buttonpanel = Gtk::manage (new Gtk::HBox ()); - buttonpanel->set_spacing(8); - mainvb->pack_start (*buttonpanel, Gtk::PACK_SHRINK, 0); - - Gtk::Button* about = Gtk::manage (new Gtk::Button (M("GENERAL_ABOUT"))); - Gtk::Button* ok = Gtk::manage (new Gtk::Button (M("GENERAL_OK"))); - Gtk::Button* cancel = Gtk::manage (new Gtk::Button (M("GENERAL_CANCEL"))); - - about->set_image (*Gtk::manage(new RTImage ("rt-logo.png"))); - ok->set_image (*Gtk::manage(new RTImage ("gtk-apply.png"))); - cancel->set_image (*Gtk::manage(new RTImage ("gtk-cancel.png"))); - - - about->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::aboutPressed) ); - ok->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::okPressed) ); - cancel->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::cancelPressed) ); - - buttonpanel->pack_start (*about, Gtk::PACK_SHRINK, 0); - buttonpanel->pack_end (*ok, Gtk::PACK_SHRINK, 0); - buttonpanel->pack_end (*cancel, Gtk::PACK_SHRINK, 0); - nb->append_page (*getGeneralPanel(), M("PREFERENCES_TAB_GENERAL")); - nb->append_page (*getProcParamsPanel(), M("PREFERENCES_TAB_IMPROC")); - nb->append_page (*getFileBrowserPanel(), M("PREFERENCES_TAB_BROWSER")); - nb->append_page (*getColorManagementPanel(),M("PREFERENCES_TAB_COLORMGR")); - nb->append_page (*getBatchProcPanel(), M("PREFERENCES_BATCH_PROCESSING")); - nb->append_page (*getPerformancePanel(), M("PREFERENCES_TAB_PERFORMANCE")); - // Sounds only on Windows and Linux -#if defined(WIN32) || defined(__linux__) - nb->append_page (*getSoundPanel(), M("PREFERENCES_TAB_SOUND")); -#endif - nb->set_current_page (0); - - profileStore.addListener(this); - - fillPreferences (); - - show_all_children (); - set_modal (true); -} - - -Preferences::~Preferences () { - - profileStore.removeListener(this); - options.preferencesWidth = get_width(); - options.preferencesHeight = get_height(); -} - -Gtk::Widget* Preferences::getBatchProcPanel () { - - Gtk::VBox* mvbpp = Gtk::manage (new Gtk::VBox ()); - mvbpp->set_border_width(4); - - Gtk::ScrolledWindow* behscrollw = Gtk::manage (new Gtk::ScrolledWindow ()); - behscrollw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); - behscrollw->set_border_width(8); - behscrollw->set_size_request(-1, 60); - Gtk::VBox* vbbeh = Gtk::manage( new Gtk::VBox () ); - vbbeh->pack_start (*behscrollw, Gtk::PACK_EXPAND_WIDGET); - Gtk::Frame* behFrame = Gtk::manage (new Gtk::Frame (M("PREFERENCES_BEHAVIOR"))); - behFrame->add (*vbbeh); - //mvbpp->pack_start (*behFrame); - mvbpp->pack_start (*behFrame, Gtk::PACK_EXPAND_WIDGET, 4); - Gtk::TreeView* behTreeView = Gtk::manage (new Gtk::TreeView ()); - behscrollw->add (*behTreeView); - - behModel = Gtk::TreeStore::create (behavColumns); - behTreeView->set_model (behModel); - - behTreeView->append_column (M("PREFERENCES_PROPERTY"), behavColumns.label); - behTreeView->append_column_editable (M("PREFERENCES_ADD"), behavColumns.badd); - behTreeView->append_column_editable (M("PREFERENCES_SET"), behavColumns.bset); - - Gtk::CellRendererToggle* cr_add = static_cast (behTreeView->get_column (1)->get_first_cell_renderer()); - Gtk::CellRendererToggle* cr_set = static_cast (behTreeView->get_column (2)->get_first_cell_renderer()); - - cr_add->set_radio (true); - cr_add->set_property("xalign", 0.0f); - sigc::connection addc = cr_add->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::behAddRadioToggled)); - cr_set->set_radio (true); - cr_set->set_property("xalign", 0.0f); - sigc::connection setc = cr_set->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::behSetRadioToggled)); - - behTreeView->get_column (1)->add_attribute (*cr_add, "visible", behavColumns.visible); - behTreeView->get_column (1)->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED); - behTreeView->get_column (1)->set_fixed_width (50); - behTreeView->get_column (2)->add_attribute (*cr_set, "visible", behavColumns.visible); - behTreeView->get_column (2)->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED); - behTreeView->get_column (2)->set_fixed_width (50); - - // fill model - Gtk::TreeModel::iterator mi, ci; - - /* - * The TRUE/FALSE values of appendBehavList are replaced by the one defined in options.cc, - */ - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_EXPOSURE_LABEL")); - appendBehavList (mi, M("TP_EXPOSURE_EXPCOMP"), ADDSET_TC_EXPCOMP, false); - appendBehavList (mi, M("TP_EXPOSURE_COMPRHIGHLIGHTS"), ADDSET_TC_HLCOMPAMOUNT, false); - appendBehavList (mi, M("TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD"), ADDSET_TC_HLCOMPTHRESH, false); - appendBehavList (mi, M("TP_EXPOSURE_BLACKLEVEL"), ADDSET_TC_BLACKLEVEL, false); - appendBehavList (mi, M("TP_EXPOSURE_COMPRSHADOWS"), ADDSET_TC_SHCOMP, false); - appendBehavList (mi, M("TP_EXPOSURE_BRIGHTNESS"), ADDSET_TC_BRIGHTNESS, false); - appendBehavList (mi, M("TP_EXPOSURE_CONTRAST"), ADDSET_TC_CONTRAST, false); - appendBehavList (mi, M("TP_EXPOSURE_SATURATION"), ADDSET_TC_SATURATION, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_SHADOWSHLIGHTS_LABEL")); - appendBehavList (mi, M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), ADDSET_SH_HIGHLIGHTS, false); - appendBehavList (mi, M("TP_SHADOWSHLIGHTS_SHADOWS"), ADDSET_SH_SHADOWS, false); - appendBehavList (mi, M("TP_SHADOWSHLIGHTS_LOCALCONTR"), ADDSET_SH_LOCALCONTRAST, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_LABCURVE_LABEL")); - appendBehavList (mi, M("TP_LABCURVE_BRIGHTNESS"), ADDSET_LC_BRIGHTNESS, false); - appendBehavList (mi, M("TP_LABCURVE_CONTRAST"), ADDSET_LC_CONTRAST, false); - appendBehavList (mi, M("TP_LABCURVE_CHROMATICITY"), ADDSET_LC_CHROMATICITY, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_SHARPENING_LABEL")); - appendBehavList (mi, M("TP_SHARPENING_AMOUNT"), ADDSET_SHARP_AMOUNT, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_SHARPENEDGE_LABEL")); - appendBehavList (mi, M("TP_SHARPENEDGE_PASSES"), ADDSET_SHARPENEDGE_PASS, false); - appendBehavList (mi, M("TP_SHARPENEDGE_AMOUNT"), ADDSET_SHARPENEDGE_AMOUNT, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_SHARPENMICRO_LABEL")); - appendBehavList (mi, M("TP_SHARPENMICRO_AMOUNT"), ADDSET_SHARPENMICRO_AMOUNT, false); - appendBehavList (mi, M("TP_SHARPENMICRO_UNIFORMITY"), ADDSET_SHARPENMICRO_UNIFORMITY, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_DIRPYRDENOISE_LABEL")); - // appendBehavList (mi, M("TP_DIRPYRDENOISE_LUMA")+", "+M("TP_DIRPYRDENOISE_CHROMA"), ADDSET_DIRPYRDN_CHLUM, true); - appendBehavList (mi, M("TP_DIRPYRDENOISE_LUMA"),ADDSET_DIRPYRDN_LUMA, true); - appendBehavList (mi, M("TP_DIRPYRDENOISE_LDETAIL"),ADDSET_DIRPYRDN_LUMDET, true); - appendBehavList (mi, M("TP_DIRPYRDENOISE_CHROMA"), ADDSET_DIRPYRDN_CHROMA, true); - appendBehavList (mi, M("TP_DIRPYRDENOISE_RED"), ADDSET_DIRPYRDN_CHROMARED, true); - appendBehavList (mi, M("TP_DIRPYRDENOISE_BLUE"), ADDSET_DIRPYRDN_CHROMABLUE, true); - appendBehavList (mi, M("TP_DIRPYRDENOISE_GAMMA"), ADDSET_DIRPYRDN_GAMMA, true); - appendBehavList (mi, M("TP_DIRPYRDENOISE_PASSES"), ADDSET_DIRPYRDN_PASSES, true); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_WBALANCE_LABEL")); - appendBehavList (mi, M("TP_WBALANCE_TEMPERATURE"), ADDSET_WB_TEMPERATURE, true); - appendBehavList (mi, M("TP_WBALANCE_GREEN"), ADDSET_WB_GREEN, true); - appendBehavList (mi, M("TP_WBALANCE_EQBLUERED"), ADDSET_WB_EQUAL, true); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_COLORAPP_LABEL")); - appendBehavList (mi, M("TP_COLORAPP_CIECAT_DEGREE"),ADDSET_CAT_DEGREE, true); - appendBehavList (mi, M("TP_COLORAPP_ADAPTSCENE"),ADDSET_CAT_ADAPTSCENE, true); - appendBehavList (mi, M("TP_COLORAPP_LIGHT"),ADDSET_CAT_LIGHT, true); - appendBehavList (mi, M("TP_COLORAPP_BRIGHT"),ADDSET_CAT_BRIGHT, true); - appendBehavList (mi, M("TP_COLORAPP_CHROMA"),ADDSET_CAT_CHROMA, true); - appendBehavList (mi, M("TP_COLORAPP_RSTPRO"),ADDSET_CAT_RSTPRO, true); - appendBehavList (mi, M("TP_COLORAPP_CONTRAST"),ADDSET_CAT_CONTRAST, true); - appendBehavList (mi, M("TP_COLORAPP_CONTRAST_Q"),ADDSET_CAT_CONTRAST_Q, true); - appendBehavList (mi, M("TP_COLORAPP_CHROMA_S"),ADDSET_CAT_CHROMA_S, true); - appendBehavList (mi, M("TP_COLORAPP_CHROMA_M"),ADDSET_CAT_CHROMA_M, true); - appendBehavList (mi, M("TP_COLORAPP_HUE"),ADDSET_CAT_HUE, true); - appendBehavList (mi, M("TP_COLORAPP_ADAPTVIEWING"),ADDSET_CAT_ADAPTVIEWING, true); - appendBehavList (mi, M("TP_COLORAPP_BADPIXSL"),ADDSET_CAT_BADPIX, true); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_VIBRANCE_LABEL")); - appendBehavList (mi, M("TP_VIBRANCE_PASTELS"), ADDSET_VIBRANCE_PASTELS, false); - appendBehavList (mi, M("TP_VIBRANCE_SATURATED"), ADDSET_VIBRANCE_SATURATED, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_GAMMA_OUTPUT")); - appendBehavList (mi, M("TP_GAMMA_CURV"), ADDSET_FREE_OUPUT_GAMMA, false); - appendBehavList (mi, M("TP_GAMMA_SLOP"), ADDSET_FREE_OUTPUT_SLOPE, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_CHMIXER_LABEL")); - appendBehavList (mi, M("TP_CHMIXER_RED")+", "+M("TP_CHMIXER_GREEN")+", "+M("TP_CHMIXER_BLUE"), ADDSET_CHMIXER, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_BWMIX_LABEL")); - appendBehavList (mi, M("TP_BWMIX_MIXC"), ADDSET_BLACKWHITE_HUES, false); - appendBehavList (mi, M("TP_BWMIX_GAMMA"), ADDSET_BLACKWHITE_GAMMA, false); - - mi = behModel->append (); - mi->set_value( behavColumns.label, M("TP_FILMSIMULATION_LABEL") ); - appendBehavList( mi, M( "TP_FILMSIMULATION_STRENGTH" ), ADDSET_FILMSIMULATION_STRENGTH, true ); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_COLORTONING_LABEL")); - appendBehavList (mi, M("TP_COLORTONING_SPLITCOCO"),ADDSET_COLORTONING_SPLIT , true); - appendBehavList (mi, M("TP_COLORTONING_SATURATIONTHRESHOLD"),ADDSET_COLORTONING_SATTHRESHOLD , true); - appendBehavList (mi, M("TP_COLORTONING_SATURATEDOPACITY"),ADDSET_COLORTONING_SATOPACITY , true); - appendBehavList (mi, M("TP_COLORTONING_BALANCE"),ADDSET_COLORTONING_BALANCE , true); - appendBehavList (mi, M("TP_COLORTONING_STRENGTH"),ADDSET_COLORTONING_STRENGTH , true); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_ROTATE_LABEL")); - appendBehavList (mi, M("TP_ROTATE_DEGREE"), ADDSET_ROTATE_DEGREE, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_DISTORTION_LABEL")); - appendBehavList (mi, M("TP_DISTORTION_AMOUNT"), ADDSET_DIST_AMOUNT, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_PERSPECTIVE_LABEL")); - appendBehavList (mi, M("TP_PERSPECTIVE_HORIZONTAL")+", "+M("TP_PERSPECTIVE_VERTICAL"), ADDSET_PERSPECTIVE, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_GRADIENT_LABEL")); - appendBehavList (mi, M("TP_GRADIENT_DEGREE"), ADDSET_GRADIENT_DEGREE, false); - appendBehavList (mi, M("TP_GRADIENT_FEATHER"), ADDSET_GRADIENT_FEATHER, false); - appendBehavList (mi, M("TP_GRADIENT_STRENGTH"), ADDSET_GRADIENT_STRENGTH, false); - appendBehavList (mi, M("TP_GRADIENT_CENTER_X")+", "+M("TP_GRADIENT_CENTER_Y"), ADDSET_GRADIENT_CENTER, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_PCVIGNETTE_LABEL")); - appendBehavList (mi, M("TP_PCVIGNETTE_STRENGTH"), ADDSET_PCVIGNETTE_STRENGTH, false); - appendBehavList (mi, M("TP_PCVIGNETTE_FEATHER"), ADDSET_PCVIGNETTE_FEATHER, false); - appendBehavList (mi, M("TP_PCVIGNETTE_ROUNDNESS"), ADDSET_PCVIGNETTE_ROUNDNESS, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_CACORRECTION_LABEL")); - appendBehavList (mi, M("TP_CACORRECTION_BLUE")+", "+M("TP_CACORRECTION_RED"), ADDSET_CA, true); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_VIGNETTING_LABEL")); - appendBehavList (mi, M("TP_VIGNETTING_AMOUNT"), ADDSET_VIGN_AMOUNT, false); - appendBehavList (mi, M("TP_VIGNETTING_RADIUS"), ADDSET_VIGN_RADIUS, false); - appendBehavList (mi, M("TP_VIGNETTING_STRENGTH"), ADDSET_VIGN_STRENGTH, false); - appendBehavList (mi, M("TP_VIGNETTING_CENTER_X")+", "+M("TP_VIGNETTING_CENTER_Y"), ADDSET_VIGN_CENTER, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_DIRPYREQUALIZER_LABEL")); - appendBehavList (mi, M("TP_EXPOSURE_CONTRAST"), ADDSET_DIRPYREQ, true); - appendBehavList (mi, M("TP_DIRPYREQUALIZER_THRESHOLD"), ADDSET_DIRPYREQ_THRESHOLD, true); - appendBehavList (mi, M("TP_DIRPYREQUALIZER_SKIN"), ADDSET_DIRPYREQ_SKINPROTECT, true); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_WAVELET_LABEL")); - appendBehavList (mi, M("TP_WAVELET_LEVELS"), ADDSET_WA_THRES, true); - // appendBehavList (mi, M("TP_WAVELET_CONTRAST"), ADDSET_WA, true); - appendBehavList (mi, M("TP_WAVELET_THRESHOLD"), ADDSET_WA_THRESHOLD, true); - appendBehavList (mi, M("TP_WAVELET_THRESHOLD2"), ADDSET_WA_THRESHOLD2, true); - appendBehavList (mi, M("TP_WAVELET_CHRO"), ADDSET_WA_CHRO, true); - appendBehavList (mi, M("TP_WAVELET_CHR"), ADDSET_WA_CHROMA, true); - appendBehavList (mi, M("TP_WAVELET_SKIN"), ADDSET_WA_SKINPROTECT, true); - appendBehavList (mi, M("TP_WAVELET_EDRAD"), ADDSET_WA_EDGRAD, true); - appendBehavList (mi, M("TP_WAVELET_EDVAL"), ADDSET_WA_EDGVAL, true); - appendBehavList (mi, M("TP_WAVELET_RESCON"), ADDSET_WA_RESCON, true); - appendBehavList (mi, M("TP_WAVELET_THR"), ADDSET_WA_THRR, true); - appendBehavList (mi, M("TP_WAVELET_RESCONH"), ADDSET_WA_RESCONH, true); - appendBehavList (mi, M("TP_WAVELET_THRH"), ADDSET_WA_THRRH, true); - appendBehavList (mi, M("TP_WAVELET_RESCHRO"), ADDSET_WA_RESCHRO, true); - appendBehavList (mi, M("TP_WAVELET_TMSTRENGTH"), ADDSET_WA_TMRS, true); - appendBehavList (mi, M("TP_WAVELET_SKY"), ADDSET_WA_SKYPROTECT, true); - appendBehavList (mi, M("TP_WAVELET_CONTRA"), ADDSET_WA_CONTRAST, true); - appendBehavList (mi, M("TP_WAVELET_STRENGTH"), ADDSET_WA_STRENGTH, true); - appendBehavList (mi, M("TP_WAVELET_COMPGAMMA"), ADDSET_WA_GAMMA, true); - appendBehavList (mi, M("TP_WAVELET_EDGEDETECT"), ADDSET_WA_EDGEDETECT, true); - appendBehavList (mi, M("TP_WAVELET_EDGEDETECTTHR"), ADDSET_WA_EDGEDETECTTHR, true); - appendBehavList (mi, M("TP_WAVELET_EDGEDETECTTHR2"), ADDSET_WA_EDGEDETECTTHR2, true); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_PREPROCESS_LABEL")); - appendBehavList (mi, M("TP_PREPROCESS_GREENEQUIL"), ADDSET_PREPROCESS_GREENEQUIL, false); - appendBehavList (mi, M("TP_PREPROCESS_LINEDENOISE"), ADDSET_PREPROCESS_LINEDENOISE, true); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_EXPOS_WHITEPOINT_LABEL")); - appendBehavList (mi, M("TP_RAWEXPOS_LINEAR"), ADDSET_RAWEXPOS_LINEAR, false); - appendBehavList (mi, M("TP_RAWEXPOS_PRESER"), ADDSET_RAWEXPOS_PRESER, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_RAWEXPOS_BLACKS")); - appendBehavList (mi, M("TP_RAWEXPOS_RGB"), ADDSET_RAWEXPOS_BLACKS, false); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_FLATFIELD_LABEL")); - appendBehavList (mi, M("TP_FLATFIELD_CLIPCONTROL"), ADDSET_RAWFFCLIPCONTROL, true); - - mi = behModel->append (); - mi->set_value (behavColumns.label, M("TP_CHROMATABERR_LABEL")); - appendBehavList (mi, M("TP_RAWCACORR_CARED")+", "+M("TP_RAWCACORR_CABLUE"), ADDSET_RAWCACORR, true); - - behTreeView->expand_all (); - - behAddAll = Gtk::manage( new Gtk::Button (M("PREFERENCES_BEHADDALL")) ); - behSetAll = Gtk::manage( new Gtk::Button (M("PREFERENCES_BEHSETALL")) ); - behAddAll->set_tooltip_markup (M("PREFERENCES_BEHADDALLHINT")); - behSetAll->set_tooltip_markup (M("PREFERENCES_BEHSETALLHINT")); - - behAddAll->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::behAddAllPressed) ); - behSetAll->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::behSetAllPressed) ); - - Gtk::HBox* buttonpanel1 = Gtk::manage (new Gtk::HBox ()); - //buttonpanel1->set_spacing(8); - buttonpanel1->pack_end (*behSetAll, Gtk::PACK_SHRINK, 4); - buttonpanel1->pack_end (*behAddAll, Gtk::PACK_SHRINK, 4); - vbbeh->pack_start (*buttonpanel1, Gtk::PACK_SHRINK, 4); - - chOverwriteOutputFile = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_OVERWRITEOUTPUTFILE")) ); - mvbpp->pack_start(*chOverwriteOutputFile, Gtk::PACK_SHRINK, 4); - - return mvbpp; -} - -void Preferences::appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, int id, bool set) { - - Gtk::TreeModel::iterator ci = behModel->append (parent->children()); - ci->set_value (behavColumns.label, label); - ci->set_value (behavColumns.visible, true); - ci->set_value (behavColumns.badd, !set); - ci->set_value (behavColumns.bset, set); - ci->set_value (behavColumns.addsetid, id); -} - -void Preferences::behAddRadioToggled (const Glib::ustring& path) { - - Gtk::TreeModel::iterator iter = behModel->get_iter (path); - //bool set = iter->get_value (behavColumns.bset); - iter->set_value (behavColumns.bset, false); - iter->set_value (behavColumns.badd, true); -} - -void Preferences::behSetRadioToggled (const Glib::ustring& path) { - - Gtk::TreeModel::iterator iter = behModel->get_iter (path); - //bool add = iter->get_value (behavColumns.badd); - iter->set_value (behavColumns.bset, true); - iter->set_value (behavColumns.badd, false); -} - -Gtk::Widget* Preferences::getProcParamsPanel () { - - Gtk::VBox* mvbpp = Gtk::manage (new Gtk::VBox ()); - - Gtk::Frame* fpp = Gtk::manage (new Gtk::Frame (M("PREFERENCES_IMPROCPARAMS"))); - Gtk::VBox* vbpp = Gtk::manage (new Gtk::VBox ()); - vbpp->set_border_width(4); - Gtk::Label* drlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_FORRAW")+":", Gtk::ALIGN_LEFT)); - rprofiles = Gtk::manage (new ProfileStoreComboBox ()); - rprofiles->set_size_request(50, -1); - rpconn = rprofiles->signal_changed().connect( sigc::mem_fun(*this, &Preferences::forRAWComboChanged) ); - Gtk::Label* drimg = Gtk::manage (new Gtk::Label (M("PREFERENCES_FORIMAGE")+":", Gtk::ALIGN_LEFT)); - iprofiles = Gtk::manage (new ProfileStoreComboBox ()); - iprofiles->set_size_request(50, -1); - ipconn = iprofiles->signal_changed().connect( sigc::mem_fun(*this, &Preferences::forImageComboChanged) ); - Gtk::Table* defpt = Gtk::manage (new Gtk::Table (2, 2)); - defpt->attach (*drlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - defpt->attach (*rprofiles, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - defpt->attach (*drimg, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - defpt->attach (*iprofiles, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - vbpp->pack_start (*defpt, Gtk::PACK_SHRINK, 4); - useBundledProfiles = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_USEBUNDLEDPROFILES"))); - bpconn = useBundledProfiles->signal_clicked().connect ( sigc::mem_fun(*this, &Preferences::bundledProfilesChanged) ); - vbpp->pack_start (*useBundledProfiles, Gtk::PACK_SHRINK, 4); - fpp->add (*vbpp); - mvbpp->pack_start (*fpp, Gtk::PACK_SHRINK, 4); - - // Custom profile builder box - Gtk::Frame* cpfrm = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CUSTPROFBUILD")) ); - Gtk::Label* cplab = Gtk::manage( new Gtk::Label (M("PREFERENCES_CUSTPROFBUILDPATH")+":", Gtk::ALIGN_LEFT) ); - txtCustProfBuilderPath = Gtk::manage( new Gtk::Entry () ); - txtCustProfBuilderPath->set_tooltip_markup (M("PREFERENCES_CUSTPROFBUILDHINT")); - Gtk::Label* cpltypelab = Gtk::manage( new Gtk::Label (M("PREFERENCES_CUSTPROFBUILDKEYFORMAT")+":", Gtk::ALIGN_LEFT) ); - custProfBuilderLabelType = Gtk::manage (new Gtk::ComboBoxText ()); - custProfBuilderLabelType->append_text (M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_TID")); - custProfBuilderLabelType->append_text (M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_NAME")); - custProfBuilderLabelType->append_text (M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_TID") + "_" + M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_NAME")); - Gtk::Table* cpbt = Gtk::manage (new Gtk::Table (2, 2)); - cpbt->set_border_width(4); - cpbt->attach (*cplab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - cpbt->attach (*txtCustProfBuilderPath, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - cpbt->attach (*cpltypelab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - cpbt->attach (*custProfBuilderLabelType, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - cpfrm->add (*cpbt); - mvbpp->pack_start (*cpfrm, Gtk::PACK_SHRINK, 4); - - Gtk::Frame* fdp = Gtk::manage (new Gtk::Frame (M("PREFERENCES_PROFILEHANDLING"))); - Gtk::VBox* vbdp = Gtk::manage (new Gtk::VBox ()); - vbdp->set_border_width (4); - saveParamsFile = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_PROFILESAVEINPUT"))); - vbdp->pack_start (*saveParamsFile, Gtk::PACK_SHRINK, 4); - saveParamsCache = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_PROFILESAVECACHE"))); - vbdp->pack_start (*saveParamsCache, Gtk::PACK_SHRINK, 4); - Gtk::Label* lplab = Gtk::manage (new Gtk::Label (M("PREFERENCES_PROFILELOADPR")+":")); - loadParamsPreference = Gtk::manage (new Gtk::ComboBoxText ()); - loadParamsPreference->append_text (M("PREFERENCES_PROFILEPRCACHE")); - loadParamsPreference->append_text (M("PREFERENCES_PROFILEPRFILE")); - Gtk::HBox* hb41 = Gtk::manage (new Gtk::HBox ()); - hb41->pack_start (*lplab, Gtk::PACK_SHRINK, 0); - hb41->pack_start (*loadParamsPreference, Gtk::PACK_EXPAND_WIDGET, 0); - hb41->set_spacing(4); - vbdp->pack_start (*hb41, Gtk::PACK_EXPAND_WIDGET, 4); - fdp->add (*vbdp); - mvbpp->pack_start (*fdp, Gtk::PACK_SHRINK, 4); - - Gtk::Frame* fdf = Gtk::manage (new Gtk::Frame (M("PREFERENCES_DARKFRAME")) ); - Gtk::HBox* hb42 = Gtk::manage (new Gtk::HBox ()); - darkFrameDir = Gtk::manage(new Gtk::FileChooserButton(M("PREFERENCES_DIRDARKFRAMES"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); - Gtk::Label *dfLab = Gtk::manage(new Gtk::Label(M("PREFERENCES_DIRDARKFRAMES")+":")); - hb42->pack_start(*dfLab , Gtk::PACK_SHRINK, 4 ); - hb42->pack_start(*darkFrameDir, Gtk::PACK_EXPAND_WIDGET, 4); - dfLabel = Gtk::manage(new Gtk::Label("Found:")); - Gtk::VBox* vbdf = Gtk::manage (new Gtk::VBox ()); - vbdf->pack_start( *hb42, Gtk::PACK_SHRINK, 4); - vbdf->pack_start( *dfLabel, Gtk::PACK_SHRINK, 4 ); - fdf->add( *vbdf ); - mvbpp->pack_start ( *fdf , Gtk::PACK_SHRINK, 4); - mvbpp->set_border_width (4); - - //dfconn = darkFrameDir->signal_file_set().connect ( sigc::mem_fun(*this, &Preferences::darkFrameChanged), true); - dfconn = darkFrameDir->signal_current_folder_changed().connect ( sigc::mem_fun(*this, &Preferences::darkFrameChanged), true); - - // FLATFIELD - Gtk::Frame* fff = Gtk::manage (new Gtk::Frame (M("PREFERENCES_FLATFIELD")) ); - Gtk::HBox* hb43 = Gtk::manage (new Gtk::HBox ()); - flatFieldDir = Gtk::manage(new Gtk::FileChooserButton(M("PREFERENCES_FLATFIELDSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); - Gtk::Label *ffLab = Gtk::manage(new Gtk::Label(M("PREFERENCES_FLATFIELDSDIR")+":")); - hb43->pack_start(*ffLab , Gtk::PACK_SHRINK, 4 ); - hb43->pack_start(*flatFieldDir); - ffLabel = Gtk::manage(new Gtk::Label("Found:")); - Gtk::VBox* vbff = Gtk::manage (new Gtk::VBox ()); - vbff->pack_start( *hb43, Gtk::PACK_SHRINK, 4); - vbff->pack_start( *ffLabel, Gtk::PACK_SHRINK, 4 ); - fff->add( *vbff ); - mvbpp->pack_start ( *fff , Gtk::PACK_SHRINK, 4); - mvbpp->set_border_width (4); - - //ffconn = flatFieldDir->signal_file_set().connect ( sigc::mem_fun(*this, &Preferences::flatFieldChanged), true); - ffconn = flatFieldDir->signal_current_folder_changed().connect ( sigc::mem_fun(*this, &Preferences::flatFieldChanged), true); - - //Cluts Dir - Gtk::Frame* clutsDirFrame = Gtk::manage (new Gtk::Frame (M("PREFERENCES_FILMSIMULATION")) ); - Gtk::HBox* clutsDirBox = Gtk::manage (new Gtk::HBox ()); - clutsDir = Gtk::manage(new Gtk::FileChooserButton(M("PREFERENCES_CLUTSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); - Gtk::Label *clutsDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_CLUTSDIR") + ":")); - Gtk::Label* clutsRestartNeeded = Gtk::manage( new Gtk::Label (Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")") ); - clutsDirBox->pack_start( *clutsDirLabel, Gtk::PACK_SHRINK, 4 ); - clutsDirBox->pack_start( *clutsDir ); - clutsDirBox->pack_start( *clutsRestartNeeded, Gtk::PACK_SHRINK, 4 ); - clutsDirBox->set_border_width( 4 ); - clutsDirFrame->add( *clutsDirBox ); - mvbpp->pack_start( *clutsDirFrame, Gtk::PACK_SHRINK, 4 ); - - Gtk::Frame* fmd = Gtk::manage (new Gtk::Frame (M("PREFERENCES_METADATA"))); - Gtk::VBox* vbmd = Gtk::manage (new Gtk::VBox ()); - ckbTunnelMetaData = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_TUNNELMETADATA"))); - vbmd->pack_start (*ckbTunnelMetaData, Gtk::PACK_SHRINK, 4); - fmd->add (*vbmd); - mvbpp->pack_start (*fmd, Gtk::PACK_SHRINK, 4); - - return mvbpp; -} - -Gtk::Widget* Preferences::getPerformancePanel () { - Gtk::VBox* mainContainer = Gtk::manage( new Gtk::VBox () ); - mainContainer->set_border_width (4); - mainContainer->set_spacing(4); - - Gtk::Frame* fprevdemo = Gtk::manage (new Gtk::Frame (M("PREFERENCES_PREVDEMO"))); - Gtk::HBox* hbprevdemo = Gtk::manage (new Gtk::HBox (false, 4)); - Gtk::Label* lprevdemo = Gtk::manage (new Gtk::Label (M("PREFERENCES_PREVDEMO_LABEL"))); - cprevdemo = Gtk::manage (new Gtk::ComboBoxText ()); - cprevdemo->append_text (M("PREFERENCES_PREVDEMO_FAST")); - cprevdemo->append_text (M("PREFERENCES_PREVDEMO_SIDECAR")); - cprevdemo->set_active (1); - hbprevdemo->pack_start (*lprevdemo, Gtk::PACK_SHRINK); - hbprevdemo->pack_start (*cprevdemo); - fprevdemo->add (*hbprevdemo); - hbprevdemo->set_border_width(4); - mainContainer->pack_start (*fprevdemo, Gtk::PACK_SHRINK, 4); - - Gtk::Frame* ftiffserialize = Gtk::manage (new Gtk::Frame (M("PREFERENCES_SERIALIZE_TIFF_READ"))); - Gtk::HBox* htiffserialize = Gtk::manage (new Gtk::HBox (false, 4)); - ctiffserialize = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SERIALIZE_TIFF_READ_LABEL")) ); - ctiffserialize->set_tooltip_text(M("PREFERENCES_SERIALIZE_TIFF_READ_TOOLTIP")); - htiffserialize->pack_start (*ctiffserialize); - ftiffserialize->add (*htiffserialize); - htiffserialize->set_border_width(4); - mainContainer->pack_start (*ftiffserialize, Gtk::PACK_SHRINK, 4); - - Gtk::Frame* fclut = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CLUTSCACHE")) ); - Gtk::HBox* clutCacheSizeHB = Gtk::manage( new Gtk::HBox () ); - clutCacheSizeHB->set_border_width(4); - clutCacheSizeHB->set_spacing(4); - Gtk::Label* CLUTLl = Gtk::manage( new Gtk::Label (M("PREFERENCES_CLUTSCACHE_LABEL") + ":", Gtk::ALIGN_LEFT)); - clutCacheSizeSB = Gtk::manage( new Gtk::SpinButton () ); - clutCacheSizeSB->set_digits (0); - clutCacheSizeSB->set_increments (1, 5); - clutCacheSizeSB->set_max_length(2); // Will this be sufficient? :) -#ifdef _OPENMP - clutCacheSizeSB->set_range (1, 2*omp_get_num_procs()); -#else - clutCacheSizeSB->set_range (1, 8); -#endif - clutCacheSizeHB->pack_start (*CLUTLl, Gtk::PACK_SHRINK, 0); - clutCacheSizeHB->pack_end (*clutCacheSizeSB, Gtk::PACK_SHRINK, 0); - fclut->add (*clutCacheSizeHB); - mainContainer->pack_start (*fclut, Gtk::PACK_SHRINK, 4); - - Gtk::Frame* finspect = Gtk::manage( new Gtk::Frame (M("PREFERENCES_INSPECT_LABEL")) ); - Gtk::HBox* maxIBuffersHB = Gtk::manage( new Gtk::HBox () ); - maxIBuffersHB->set_border_width(4); - maxIBuffersHB->set_spacing(4); - maxIBuffersHB->set_tooltip_text(M("PREFERENCES_INSPECT_MAXBUFFERS_TOOLTIP")); - Gtk::Label* maxIBufferLbl = Gtk::manage( new Gtk::Label (M("PREFERENCES_INSPECT_MAXBUFFERS_LABEL") + ":", Gtk::ALIGN_LEFT)); - maxInspectorBuffersSB = Gtk::manage( new Gtk::SpinButton () ); - maxInspectorBuffersSB->set_digits (0); - maxInspectorBuffersSB->set_increments (1, 5); - maxInspectorBuffersSB->set_max_length(2); - maxInspectorBuffersSB->set_range (1, 12); // ... we have to set a limit, 12 seem to be enough even for systems with tons of RAM - maxIBuffersHB->pack_start (*maxIBufferLbl, Gtk::PACK_SHRINK, 0); - maxIBuffersHB->pack_end (*maxInspectorBuffersSB, Gtk::PACK_SHRINK, 0); - finspect->add(*maxIBuffersHB); - mainContainer->pack_start(*finspect, Gtk::PACK_SHRINK, 4); - - Gtk::Frame* fdenoise = Gtk::manage( new Gtk::Frame (M("PREFERENCES_NOISE")) ); - Gtk::VBox* vbdenoise = Gtk::manage( new Gtk::VBox (Gtk::PACK_SHRINK, 4) ); - vbdenoise->set_border_width (4); - - Gtk::Label* lreloadneeded2 = Gtk::manage (new Gtk::Label (M("PREFERENCES_IMG_RELOAD_NEEDED"), Gtk::ALIGN_LEFT)); - Gtk::HBox* threadLimitHB = Gtk::manage (new Gtk::HBox (Gtk::PACK_SHRINK, 4)); - threadLimitHB->set_tooltip_text(M("PREFERENCES_RGBDTL_TOOLTIP")); - Gtk::Label* RGBDTLl = Gtk::manage( new Gtk::Label (M("PREFERENCES_RGBDTL_LABEL") + ":", Gtk::ALIGN_LEFT)); - rgbDenoiseTreadLimitSB = Gtk::manage( new Gtk::SpinButton () ); - rgbDenoiseTreadLimitSB->set_digits (0); - rgbDenoiseTreadLimitSB->set_increments (1, 5); - rgbDenoiseTreadLimitSB->set_max_length(2); // Will this be sufficient? :) - int maxThreadNumber = 10; -#ifdef _OPENMP - maxThreadNumber = omp_get_max_threads(); -#endif - rgbDenoiseTreadLimitSB->set_range (0, maxThreadNumber); - threadLimitHB->pack_start (*RGBDTLl, Gtk::PACK_SHRINK, 2); - threadLimitHB->pack_end (*rgbDenoiseTreadLimitSB, Gtk::PACK_SHRINK, 2); - - Gtk::Label* dnlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_LEVDN")+":", Gtk::ALIGN_LEFT)); - Gtk::Label* dnautlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_LEVAUTDN")+":", Gtk::ALIGN_LEFT)); - Gtk::Label* dnautsimpllab = Gtk::manage (new Gtk::Label (M("PREFERENCES_SIMPLAUT")+":", Gtk::ALIGN_LEFT)); - Gtk::Label* dntilab = Gtk::manage (new Gtk::Label (M("PREFERENCES_TINB")+":", Gtk::ALIGN_LEFT)); - Gtk::Label* dnwavlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_WAVLEV")+":", Gtk::ALIGN_LEFT)); - Gtk::Label* dnlisslab = Gtk::manage (new Gtk::Label (M("PREFERENCES_LISS")+":", Gtk::ALIGN_LEFT)); - - dnv = Gtk::manage (new Gtk::ComboBoxText ()); - dnv->append_text (M("PREFERENCES_MIN")); - dnv->append_text (M("PREFERENCES_SMA")); - dnv->append_text (M("PREFERENCES_MED")); - dnv->append_text (M("PREFERENCES_MAX")); - dnaut = Gtk::manage (new Gtk::ComboBoxText ()); - dnaut->append_text (M("PREFERENCES_AUTLOW")); - dnaut->append_text (M("PREFERENCES_AUTSTD")); - - dnautsimpl = Gtk::manage (new Gtk::ComboBoxText ()); - dnautsimpl->append_text (M("PREFERENCES_STDAUT")); - dnautsimpl->append_text (M("PREFERENCES_EXPAUT")); - - dnliss = Gtk::manage (new Gtk::ComboBoxText ()); - dnliss->append_text (M("PREFERENCES_AUTLISVLOW"));//very low - dnliss->append_text (M("PREFERENCES_AUTLISLOW"));//low - dnliss->append_text (M("PREFERENCES_AUTLISSTD"));//med - dnliss->append_text (M("PREFERENCES_AUTLISMAX"));//max - - dnti = Gtk::manage (new Gtk::ComboBoxText ()); - dnti->append_text (M("PREFERENCES_TISTD")); - dnti->append_text (M("PREFERENCES_TIMAX")); - - dnwavlev = Gtk::manage (new Gtk::ComboBoxText ()); - dnwavlev->append_text (M("PREFERENCES_WLZER")); - dnwavlev->append_text (M("PREFERENCES_WLONE")); - dnwavlev->append_text (M("PREFERENCES_WLTWO")); - - Gtk::Table* colon = Gtk::manage (new Gtk::Table (6, 2)); - colon->attach (*dnlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - colon->attach (*dnv, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - colon->attach (*dnautlab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - colon->attach (*dnaut, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - colon->attach (*dnautsimpllab, 0, 1, 2, 3, Gtk::FILL, Gtk::SHRINK, 2, 2); - colon->attach (*dnautsimpl, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - colon->attach (*dnlisslab, 0, 1, 3, 4, Gtk::FILL, Gtk::SHRINK, 2, 2); - colon->attach (*dnliss, 1, 2, 3, 4, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - colon->attach (*dntilab, 0, 1, 4, 5, Gtk::FILL, Gtk::SHRINK, 2, 2); - colon->attach (*dnti, 1, 2, 4, 5, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - colon->attach (*dnwavlab, 0, 1, 5, 6, Gtk::FILL, Gtk::SHRINK, 2, 2); - colon->attach (*dnwavlev, 1, 2, 5, 6, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - - vbdenoise->pack_start (*lreloadneeded2, Gtk::PACK_SHRINK); - vbdenoise->pack_start (*colon, Gtk::PACK_SHRINK); - vbdenoise->pack_start(*threadLimitHB, Gtk::PACK_SHRINK); - // <--- To be hard-coded and removed once tested - cbdaubech = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_DAUB_LABEL"), Gtk::ALIGN_LEFT)); - cbdaubech->set_tooltip_markup (M("PREFERENCES_DAUB_TOOLTIP")); - // vbdenoise->pack_start (*cbdaubech, Gtk::PACK_SHRINK); - // ---> - fdenoise->add (*vbdenoise); - mainContainer->pack_start (*fdenoise, Gtk::PACK_SHRINK, 4); - - return mainContainer; -} - -Gtk::Widget* Preferences::getColorManagementPanel () { - - Gtk::VBox* mvbcm = Gtk::manage (new Gtk::VBox ()); - mvbcm->set_border_width (4); - - Gtk::Label* intlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_CMETRICINTENT")+":", Gtk::ALIGN_LEFT)); - intent = Gtk::manage (new Gtk::ComboBoxText ()); - intent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); - intent->append_text (M("PREFERENCES_INTENT_RELATIVE")); - intent->append_text (M("PREFERENCES_INTENT_SATURATION")); - intent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); - - iccDir = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_ICCDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); - Gtk::Label* pdlabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_ICCDIR")+":", Gtk::ALIGN_LEFT)); - - Gtk::FileFilter monProfileFilter_colprof; - monProfileFilter_colprof.set_name(M("FILECHOOSER_FILTER_COLPROF")); - monProfileFilter_colprof.add_pattern("*.icc"); - monProfileFilter_colprof.add_pattern("*.ICC"); - monProfileFilter_colprof.add_pattern("*.icm"); - monProfileFilter_colprof.add_pattern("*.ICM"); - Gtk::FileFilter monProfileFilter_any; - monProfileFilter_any.set_name(M("FILECHOOSER_FILTER_ANY")); - monProfileFilter_any.add_pattern("*"); - - monProfile = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_MONITORICC"), Gtk::FILE_CHOOSER_ACTION_OPEN)); - monProfile->add_filter (monProfileFilter_colprof); - monProfile->add_filter (monProfileFilter_any); - Gtk::Label* mplabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONITORICC")+":", Gtk::ALIGN_LEFT)); - -#if defined(WIN32) // Auto-detection not implemented for Linux, see issue 851 - cbAutoMonProfile = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_AUTOMONPROFILE"))); - autoMonProfileConn = cbAutoMonProfile->signal_toggled().connect (sigc::mem_fun(*this, &Preferences::autoMonProfileToggled)); -#endif - - Gtk::Table* colt = Gtk::manage (new Gtk::Table (3, 2)); - colt->attach (*intlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*intent, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - colt->attach (*pdlabel, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*iccDir, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); -#if !defined(__APPLE__) // monitor profile not supported on apple - colt->attach (*mplabel, 0, 1, 2, 3, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*monProfile, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); -#if defined(WIN32) - colt->attach (*cbAutoMonProfile, 1, 2, 3, 4, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); -#endif -#endif - mvbcm->pack_start (*colt, Gtk::PACK_SHRINK, 4); - -#if defined(WIN32) - autoMonProfileToggled(); -#endif - - Gtk::VBox* vbdp = Gtk::manage (new Gtk::VBox ()); - vbdp->set_border_width (4); - Gtk::Label* viewlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_VIEW")+":", Gtk::ALIGN_LEFT)); - - view = Gtk::manage (new Gtk::ComboBoxText ()); - view->append_text (M("PREFERENCES_D50")); - view->append_text (M("PREFERENCES_D55")); - view->append_text (M("PREFERENCES_D60")); - view->append_text (M("PREFERENCES_D65")); - view->append_text (M("PREFERENCES_BLACKBODY")); - view->append_text (M("PREFERENCES_FLUOF2")); - view->append_text (M("PREFERENCES_FLUOF7")); - view->append_text (M("PREFERENCES_FLUOF11")); - - Gtk::Label* greylab = Gtk::manage (new Gtk::Label (M("PREFERENCES_GREY")+":", Gtk::ALIGN_LEFT)); - grey = Gtk::manage (new Gtk::ComboBoxText ()); - grey->append_text (M("PREFERENCES_GREY05")); - grey->append_text (M("PREFERENCES_GREY10")); - grey->append_text (M("PREFERENCES_GREY15")); - grey->append_text (M("PREFERENCES_GREY18")); - grey->append_text (M("PREFERENCES_GREY23")); - grey->append_text (M("PREFERENCES_GREY30")); - grey->append_text (M("PREFERENCES_GREY40")); - - Gtk::Label* greySclab = Gtk::manage (new Gtk::Label (M("PREFERENCES_GREYSC")+":", Gtk::ALIGN_LEFT)); - greySc = Gtk::manage (new Gtk::ComboBoxText ()); - greySc->append_text (M("PREFERENCES_GREYSCA")); - greySc->append_text (M("PREFERENCES_GREYSC18")); - - Gtk::Frame* fcielab = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CIEART_FRAME")) ); - Gtk::VBox* vbcielab = Gtk::manage( new Gtk::VBox () ); - vbcielab->set_border_width (4); - - Gtk::Label* lreloadneeded1 = Gtk::manage (new Gtk::Label (M("PREFERENCES_IMG_RELOAD_NEEDED"), Gtk::ALIGN_LEFT)); - Gtk::Table* colo = Gtk::manage (new Gtk::Table (4, 2)); - colo->attach (*viewlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - colo->attach (*view, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - colo->attach (*greylab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - colo->attach (*grey, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - colo->attach (*greySclab, 0, 1, 2, 3, Gtk::FILL, Gtk::SHRINK, 2, 2); - colo->attach (*greySc, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - cbciecamfloat = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_CIEART_LABEL"))); - colo->attach (*cbciecamfloat, 0, 1, 3, 4, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - cbciecamfloat->set_tooltip_markup (M("PREFERENCES_CIEART_TOOLTIP")); - vbcielab->pack_start (*lreloadneeded1, Gtk::PACK_SHRINK, 4); - vbcielab->pack_start (*colo, Gtk::PACK_EXPAND_WIDGET, 4); - fcielab->add (*vbcielab); - - mvbcm->pack_start (*fcielab, Gtk::PACK_SHRINK, 4); - - return mvbcm; -} - -Gtk::Widget* Preferences::getGeneralPanel () { - - Gtk::VBox* mvbsd = Gtk::manage( new Gtk::VBox () ); - - Gtk::Frame* fworklflow = Gtk::manage (new Gtk::Frame (M("PREFERENCES_WORKFLOW"))); - Gtk::VBox* vbworkflow = Gtk::manage (new Gtk::VBox (false, 4)); - vbworkflow->set_border_width (4); - - Gtk::HBox* hbworkflow = Gtk::manage (new Gtk::HBox (false, 4)); - Gtk::Label* flayoutlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_EDITORLAYOUT")+":")); - editorLayout = Gtk::manage (new Gtk::ComboBoxText ()); - editorLayout->append_text (M("PREFERENCES_SINGLETAB")); - editorLayout->append_text (M("PREFERENCES_SINGLETABVERTAB")); - editorLayout->append_text (M("PREFERENCES_MULTITAB")); - editorLayout->append_text (M("PREFERENCES_MULTITABDUALMON")); - editorLayout->set_active (2); - editorLayout->signal_changed().connect (sigc::mem_fun(*this, &Preferences::layoutComboChanged)); - layoutComboChanged(); // update the tooltip - hbworkflow->pack_start (*flayoutlab, Gtk::PACK_SHRINK); - hbworkflow->pack_start (*editorLayout); - Gtk::Label* lNextStart = Gtk::manage( new Gtk::Label (Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")") ); - hbworkflow->pack_end (*lNextStart, Gtk::PACK_SHRINK); - vbworkflow->pack_start (*hbworkflow, Gtk::PACK_SHRINK); - - Gtk::HBox* curveBBoxPosHB = Gtk::manage (new Gtk::HBox (false, 4)); - Gtk::Label* curveBBoxPosL = Gtk::manage (new Gtk::Label (M("PREFERENCES_CURVEBBOXPOS")+":")); - Gtk::Label* curveBBoxPosRestartL = Gtk::manage (new Gtk::Label (Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")")); - curveBBoxPosC = Gtk::manage (new Gtk::ComboBoxText ()); - curveBBoxPosC->append_text (M("PREFERENCES_CURVEBBOXPOS_ABOVE")); - curveBBoxPosC->append_text (M("PREFERENCES_CURVEBBOXPOS_RIGHT")); - curveBBoxPosC->append_text (M("PREFERENCES_CURVEBBOXPOS_BELOW")); - curveBBoxPosC->append_text (M("PREFERENCES_CURVEBBOXPOS_LEFT")); - curveBBoxPosC->set_active (1); - curveBBoxPosHB->pack_start (*curveBBoxPosL, Gtk::PACK_SHRINK); - curveBBoxPosHB->pack_start (*curveBBoxPosC); - curveBBoxPosHB->pack_start (*curveBBoxPosRestartL, Gtk::PACK_SHRINK); - vbworkflow->pack_start (*curveBBoxPosHB, Gtk::PACK_SHRINK); - - Gtk::HBox* hbworkflow2 = Gtk::manage( new Gtk::HBox () ); - ckbHistogramPositionLeft = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_HISTOGRAMPOSITIONLEFT")) ); - hbworkflow2->pack_start (*ckbHistogramPositionLeft); - ckbHistogramWorking = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_HISTOGRAMWORKING")) ); - ckbHistogramWorking->set_tooltip_markup (M("PREFERENCES_HISTOGRAM_TOOLTIP")); - hbworkflow2->pack_start (*ckbHistogramWorking); - vbworkflow->pack_start (*hbworkflow2, Gtk::PACK_SHRINK); - - Gtk::HBox* hbworkflow3 = Gtk::manage( new Gtk::HBox () ); - ckbFileBrowserToolbarSingleRow = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_FILEBROWSERTOOLBARSINGLEROW")) ); - ckbShowFilmStripToolBar = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SHOWFILMSTRIPTOOLBAR")) ); - hbworkflow3->pack_start (*ckbFileBrowserToolbarSingleRow); - hbworkflow3->pack_start (*ckbShowFilmStripToolBar); - vbworkflow->pack_start (*hbworkflow3, Gtk::PACK_SHRINK); - - Gtk::HBox* hbworkflow4 = Gtk::manage( new Gtk::HBox (false, 4) ); - Gtk::Label* hb4label = Gtk::manage( new Gtk::Label (M("PREFERENCES_TP_LABEL")) ); - hbworkflow4->pack_start (*hb4label, Gtk::PACK_SHRINK); - ckbHideTPVScrollbar = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_TP_VSCROLLBAR")) ); - hbworkflow4->pack_start (*ckbHideTPVScrollbar, Gtk::PACK_SHRINK); - ckbUseIconNoText = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_TP_USEICONORTEXT")) ); - hbworkflow4->pack_start (*ckbUseIconNoText, Gtk::PACK_SHRINK); - vbworkflow->pack_start (*hbworkflow4, Gtk::PACK_SHRINK); - - fworklflow->add (*vbworkflow); - mvbsd->pack_start (*fworklflow, Gtk::PACK_SHRINK); - - Gtk::Frame* flang = Gtk::manage( new Gtk::Frame (M("PREFERENCES_DEFAULTLANG")) ); - Gtk::HBox* hblang = Gtk::manage( new Gtk::HBox () ); - hblang->set_border_width (4); - - ckbLangAutoDetect = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_LANGAUTODETECT")) ); - - Gtk::Label* langlab = Gtk::manage( new Gtk::Label (M("PREFERENCES_SELECTLANG")+":") ); - languages = Gtk::manage( new Gtk::ComboBoxText () ); - - std::vector langs; - parseDir (argv0 + "/languages", langs, ""); - for (size_t i=0; iappend_text (langs[i]); - } - } - - Gtk::Label* langw = Gtk::manage( new Gtk::Label (Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")") ); - hblang->pack_start (*ckbLangAutoDetect, Gtk::PACK_SHRINK, 4); - hblang->pack_start (*langlab, Gtk::PACK_SHRINK, 8); - hblang->pack_start (*languages); - hblang->pack_end (*langw, Gtk::PACK_SHRINK, 4); - flang->add (*hblang); - mvbsd->pack_start (*flang, Gtk::PACK_SHRINK, 4); - - langAutoDetectConn = ckbLangAutoDetect->signal_toggled().connect (sigc::mem_fun(*this, &Preferences::langAutoDetectToggled)); - - Gtk::Frame* ftheme = Gtk::manage( new Gtk::Frame (M("PREFERENCES_DEFAULTTHEME")) ); - Gtk::VBox* vbftheme = Gtk::manage( new Gtk::VBox () ); - vbftheme->set_border_width(4); - vbftheme->set_spacing(4); - Gtk::HBox* hbUseSystemTheme = Gtk::manage( new Gtk::HBox () ); - hbUseSystemTheme->set_spacing(4); - chUseSystemTheme = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_USESYSTEMTHEME")) ); - Gtk::Label* useNextStart = Gtk::manage( new Gtk::Label (Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")") ); - - Gtk::Label* cutOverlayLabel = Gtk::manage( new Gtk::Label (M("PREFERENCES_CUTOVERLAYBRUSH") + ":") ); - butCropCol= Gtk::manage( new Gtk::ColorButton() ); - butCropCol->set_use_alpha(true); - - Gtk::Label* navGuideLabel = Gtk::manage( new Gtk::Label (M("PREFERENCES_NAVGUIDEBRUSH") + ":") ); - butNavGuideCol= Gtk::manage( new Gtk::ColorButton() ); - butNavGuideCol->set_use_alpha(true); - - slimUI = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SLIMUI")) ); - hbUseSystemTheme->pack_start(*chUseSystemTheme, Gtk::PACK_SHRINK); - hbUseSystemTheme->pack_start (*useNextStart, Gtk::PACK_SHRINK, 0); - hbUseSystemTheme->pack_end(*slimUI, Gtk::PACK_SHRINK, 0); - vbftheme->pack_start(*hbUseSystemTheme, Gtk::PACK_SHRINK, 0); - - - hbtheme = Gtk::manage( new Gtk::HBox () ); - hbtheme->set_spacing (4); - Gtk::Label* themelab = Gtk::manage( new Gtk::Label (M("PREFERENCES_SELECTTHEME")+":") ); - theme = Gtk::manage( new Gtk::ComboBoxText () ); - - theme->set_active (0); - std::vector themes; - parseDir (argv0 + "/themes", themes, ".gtkrc"); - for (size_t i=0; iappend_text (themes[i]); - - Gtk::Label* fontlab = Gtk::manage( new Gtk::Label (M("PREFERENCES_SELECTFONT")+":") ); - fontbutton = Gtk::manage( new Gtk::FontButton ()); - fontbutton->set_use_size(true); - fontbutton->set_font_name(options.font); - - hbtheme->pack_start (*themelab, Gtk::PACK_SHRINK, 0); - hbtheme->pack_start (*theme); - hbtheme->pack_start (*fontlab, Gtk::PACK_SHRINK, 0); - hbtheme->pack_start (*fontbutton); - vbftheme->pack_start(*hbtheme, Gtk::PACK_SHRINK, 0); - - - Gtk::HBox* hbcolorchooser = Gtk::manage( new Gtk::HBox () ); - hbcolorchooser->set_spacing(4); - - hbcolorchooser->pack_start (*cutOverlayLabel, Gtk::PACK_SHRINK, 0); - hbcolorchooser->pack_start (*butCropCol, Gtk::PACK_SHRINK, 0); - hbcolorchooser->pack_end (*butNavGuideCol, Gtk::PACK_SHRINK, 0); - hbcolorchooser->pack_end (*navGuideLabel, Gtk::PACK_SHRINK, 0); - vbftheme->pack_start(*hbcolorchooser, Gtk::PACK_SHRINK, 0); - - - ftheme->add (*vbftheme); - mvbsd->pack_start (*ftheme, Gtk::PACK_SHRINK, 0); - -//----- - - Gtk::HBox* hbcd = Gtk::manage( new Gtk::HBox (true) ); - hbcd->set_spacing(4); - - Gtk::Frame* frl = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CLIPPINGIND"))); - Gtk::VBox* vbrl = Gtk::manage( new Gtk::VBox () ); - vbrl->set_border_width(4); - vbrl->set_spacing (4); - - Gtk::HBox* vbhl = Gtk::manage( new Gtk::HBox () ); - vbhl->set_spacing(4); - Gtk::Label* hll = Gtk::manage( new Gtk::Label (M("PREFERENCES_HLTHRESHOLD")+": ")); - hlThresh = Gtk::manage( new Gtk::SpinButton () ); - hlThresh->set_digits (0); - hlThresh->set_increments (1, 10); - hlThresh->set_range (0, 255); - vbhl->pack_start (*hll, Gtk::PACK_SHRINK, 0); - vbhl->pack_end (*hlThresh, Gtk::PACK_SHRINK, 0); - - vbrl->pack_start (*vbhl, Gtk::PACK_SHRINK, 0); - - Gtk::HBox* vbsh = Gtk::manage( new Gtk::HBox () ); - vbsh->set_spacing (4); - Gtk::Label* shl = Gtk::manage( new Gtk::Label (M("PREFERENCES_SHTHRESHOLD")+": ") ); - shThresh = Gtk::manage( new Gtk::SpinButton () ); - shThresh->show (); - shThresh->set_digits (0); - shThresh->set_increments (1, 10); - shThresh->set_range (0, 255); - vbsh->pack_start (*shl, Gtk::PACK_SHRINK, 0); - vbsh->pack_end (*shThresh, Gtk::PACK_SHRINK, 0); - vbrl->pack_start (*vbsh, Gtk::PACK_SHRINK, 0); - - frl->add (*vbrl); - hbcd->pack_start (*frl, true, true, 0); - - //--- - - Gtk::Frame* navigationFrame = Gtk::manage( new Gtk::Frame (M("PREFERENCES_NAVIGATIONFRAME")) ); - Gtk::VBox* navigationVBox = Gtk::manage( new Gtk::VBox () ); - navigationVBox->set_border_width(4); - - Gtk::HBox* panFactorHBox = Gtk::manage( new Gtk::HBox () ); - Gtk::Label* panFactorLabel = Gtk::manage( new Gtk::Label (M("PREFERENCES_PANFACTORLABEL") + ":", Gtk::ALIGN_LEFT)); - panFactor = Gtk::manage( new Gtk::SpinButton () ); - panFactor->set_digits (0); - panFactor->set_increments (1, 5); - panFactor->set_range (1, 10); - panFactorHBox->pack_start (*panFactorLabel); - panFactorHBox->pack_end (*panFactor, Gtk::PACK_SHRINK); - - rememberZoomPanCheckbutton = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_REMEMBERZOOMPAN")) ); - rememberZoomPanCheckbutton->set_tooltip_text(M("PREFERENCES_REMEMBERZOOMPAN_TOOLTIP")); - - navigationVBox->pack_start (*panFactorHBox, Gtk::PACK_SHRINK); - navigationVBox->pack_start (*rememberZoomPanCheckbutton, Gtk::PACK_SHRINK); - navigationFrame->add (*navigationVBox); - - hbcd->pack_start (*navigationFrame); - mvbsd->pack_start (*hbcd, Gtk::PACK_SHRINK, 0); - -//----- - - Gtk::Frame* fdg = Gtk::manage( new Gtk::Frame (M("PREFERENCES_EXTERNALEDITOR")) ); - Gtk::VBox* dgvb = Gtk::manage( new Gtk::VBox () ); - - Gtk::HBox* hb7c = Gtk::manage( new Gtk::HBox () ); - edOther = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_EDITORCMDLINE")+":")); - hb7c->pack_start (*edOther, Gtk::PACK_SHRINK,4); - editorToSendTo = Gtk::manage( new Gtk::Entry () ); - hb7c->pack_start (*editorToSendTo); - Gtk::RadioButton::Group ge = edOther->get_group(); - -#ifdef __APPLE__ - Gtk::HBox* hb7 = Gtk::manage( new Gtk::HBox () ); - edGimp = Gtk::manage( new Gtk::RadioButton ("GIMP") ); - hb7->pack_start (*edGimp, Gtk::PACK_SHRINK,4); - dgvb->pack_start (*hb7, Gtk::PACK_SHRINK, 4); - edGimp->set_group (ge); - - Gtk::HBox* hb7b = Gtk::manage( new Gtk::HBox () ); - edPS = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_PSPATH")+":")); - hb7b->pack_start (*edPS, Gtk::PACK_SHRINK,4); - psDir = Gtk::manage( new Gtk::FileChooserButton (M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) ); - hb7b->pack_start (*psDir); - dgvb->pack_start (*hb7b, Gtk::PACK_SHRINK, 4); - edPS->set_group (ge); -#elif defined WIN32 - Gtk::HBox* hb7 = Gtk::manage( new Gtk::HBox () ); - edGimp = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_GIMPPATH")+":") ); - hb7->pack_start (*edGimp, Gtk::PACK_SHRINK,4); - gimpDir = Gtk::manage( new Gtk::FileChooserButton (M("PREFERENCES_GIMPPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) ); - hb7->pack_start (*gimpDir); - dgvb->pack_start (*hb7, Gtk::PACK_SHRINK, 4); - edGimp->set_group (ge); - - Gtk::HBox* hb7b = Gtk::manage( new Gtk::HBox ()); - edPS = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_PSPATH")+":") ); - hb7b->pack_start (*edPS, Gtk::PACK_SHRINK,4); - psDir = Gtk::manage( new Gtk::FileChooserButton (M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) ); - hb7b->pack_start (*psDir); - dgvb->pack_start (*hb7b, Gtk::PACK_SHRINK, 4); - edPS->set_group (ge); -#else - Gtk::HBox* hb7 = Gtk::manage( new Gtk::HBox () ); - edGimp = Gtk::manage( new Gtk::RadioButton ("GIMP") ); - hb7->pack_start (*edGimp, Gtk::PACK_SHRINK,4); - dgvb->pack_start (*hb7, Gtk::PACK_SHRINK, 4); - edGimp->set_group (ge); -#endif - - dgvb->pack_start (*hb7c, Gtk::PACK_SHRINK, 4); - dgvb->set_border_width (4); - fdg->add (*dgvb); - mvbsd->pack_start (*fdg, Gtk::PACK_SHRINK, 4); - - - mvbsd->set_border_width (4); - - tconn = theme->signal_changed().connect( sigc::mem_fun(*this, &Preferences::themeChanged) ); - sconn = slimUI->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::themeChanged) ); - fconn = fontbutton->signal_font_set().connect( sigc::mem_fun(*this, &Preferences::fontChanged) ); - usethcon = chUseSystemTheme->signal_clicked ().connect( sigc::mem_fun(*this, &Preferences::useThemeChanged) ); - - return mvbsd; -} - -Gtk::Widget* Preferences::getFileBrowserPanel () { - - Gtk::VBox* mvbfb = Gtk::manage( new Gtk::VBox () ); - mvbfb->set_border_width (4); - - Gtk::Frame* fsd = Gtk::manage( new Gtk::Frame (M("PREFERENCES_STARTUPIMDIR")) ); - - sdcurrent = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_DIRSOFTWARE")) ); - sdlast = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_DIRLAST")) ); - sdhome = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_DIRHOME")) ); - sdother = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_DIROTHER")+": ") ); - startupdir = Gtk::manage( new Gtk::Entry () ); - - Gtk::Button* sdselect = Gtk::manage( new Gtk::Button ("") ); - sdselect->set_image (*Gtk::manage(new RTImage ("gtk-open.png"))); - - Gtk::RadioButton::Group opts = sdcurrent->get_group(); - sdlast->set_group (opts); - sdhome->set_group (opts); - sdother->set_group (opts); - - Gtk::VBox* vbsd = Gtk::manage( new Gtk::VBox () ); - vbsd->pack_start (*sdcurrent, Gtk::PACK_SHRINK,0); - vbsd->pack_start (*sdlast, Gtk::PACK_SHRINK,0); - vbsd->pack_start (*sdhome, Gtk::PACK_SHRINK,0); - Gtk::HBox* otherbox = Gtk::manage( new Gtk::HBox () ); - otherbox->pack_start (*sdother, Gtk::PACK_SHRINK); - otherbox->pack_start (*startupdir); - otherbox->pack_end (*sdselect, Gtk::PACK_SHRINK, 4); - vbsd->pack_start (*otherbox, Gtk::PACK_SHRINK, 0); - vbsd->set_border_width (4); - - fsd->add (*vbsd); - mvbfb->pack_start (*fsd, Gtk::PACK_SHRINK, 4); - - sdselect->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::selectStartupDir) ); - -//--- - - - Gtk::Frame* fro = Gtk::manage( new Gtk::Frame (M("PREFERENCES_FBROWSEROPTS")) ); - showDateTime = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SHOWDATETIME")) ); - showBasicExif = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SHOWBASICEXIF")) ); - showExpComp = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SHOWEXPOSURECOMPENSATION")) ); - Gtk::VBox* vbro = Gtk::manage( new Gtk::VBox () ); - Gtk::HBox* hbro1 = Gtk::manage( new Gtk::HBox () ); - Gtk::HBox* hbro0 = Gtk::manage( new Gtk::HBox () ); - overlayedFileNames = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_OVERLAY_FILENAMES")) ); - filmStripOverlayedFileNames = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_OVERLAY_FILENAMES_FILMSTRIP")) ); - sameThumbSize = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT")) ); - sameThumbSize->set_tooltip_text(M("PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT_HINT")); - ckbInternalThumbIfUntouched = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_INTERNALTHUMBIFUNTOUCHED"))); - - vbro->set_border_width (4); - vbro->pack_start (*showDateTime, Gtk::PACK_SHRINK, 0); - Gtk::Label* dflab = Gtk::manage( new Gtk::Label (M("PREFERENCES_DATEFORMAT")+":", Gtk::ALIGN_LEFT)); - dateformat = Gtk::manage( new Gtk::Entry () ); - dateformat->set_tooltip_markup (M("PREFERENCES_DATEFORMATHINT")); - dflab->set_tooltip_markup (M("PREFERENCES_DATEFORMATHINT")); - hbro0->pack_start (*dflab, Gtk::PACK_SHRINK, 4); - hbro0->pack_start (*dateformat, Gtk::PACK_SHRINK, 0); - - vbro->pack_start (*hbro0, Gtk::PACK_SHRINK, 0); - hbro1->pack_start (*showBasicExif, Gtk::PACK_SHRINK, 0); - hbro1->pack_start (*showExpComp, Gtk::PACK_SHRINK, 4); - vbro->pack_start (*hbro1, Gtk::PACK_SHRINK, 0); - vbro->pack_start (*overlayedFileNames, Gtk::PACK_SHRINK, 0); - vbro->pack_start (*filmStripOverlayedFileNames, Gtk::PACK_SHRINK, 0); - vbro->pack_start (*sameThumbSize, Gtk::PACK_SHRINK, 0); - vbro->pack_start (*ckbInternalThumbIfUntouched, Gtk::PACK_SHRINK, 0); - - Gtk::HBox* hbrecent = Gtk::manage( new Gtk::HBox () ); - Gtk::Label* labrecent = Gtk::manage( new Gtk::Label (M("PREFERENCES_MAXRECENTFOLDERS")+":") ); - maxRecentFolders = Gtk::manage( new Gtk::SpinButton () ); - hbrecent->pack_start (*labrecent, Gtk::PACK_SHRINK, 4); - hbrecent->pack_start (*maxRecentFolders, Gtk::PACK_SHRINK, 4); - maxRecentFolders->set_digits (0); - maxRecentFolders->set_increments (1, 5); - maxRecentFolders->set_range (1, 25); - vbro->pack_start (*hbrecent, Gtk::PACK_SHRINK, 4); - - fro->add (*vbro); - - - Gtk::Frame* frmnu = Gtk::manage( new Gtk::Frame (M("PREFERENCES_MENUOPTIONS")) ); - ckbmenuGroupRank = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_MENUGROUPRANK")) ); - ckbmenuGroupLabel = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_MENUGROUPLABEL")) ); - ckbmenuGroupFileOperations = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_MENUGROUPFILEOPERATIONS")) ); - ckbmenuGroupProfileOperations = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_MENUGROUPPROFILEOPERATIONS")) ); - ckbmenuGroupExtProg = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_MENUGROUPEXTPROGS")) ); - Gtk::VBox* vbmnu = Gtk::manage( new Gtk::VBox () ); - - vbmnu->set_border_width (4); - vbmnu->pack_start (*ckbmenuGroupRank, Gtk::PACK_SHRINK, 0); - vbmnu->pack_start (*ckbmenuGroupLabel, Gtk::PACK_SHRINK, 0); - vbmnu->pack_start (*ckbmenuGroupFileOperations, Gtk::PACK_SHRINK, 0); - vbmnu->pack_start (*ckbmenuGroupProfileOperations, Gtk::PACK_SHRINK, 0); - vbmnu->pack_start (*ckbmenuGroupExtProg, Gtk::PACK_SHRINK, 0); - - frmnu->add (*vbmnu); - - - Gtk::Frame* fre = Gtk::manage( new Gtk::Frame (M("PREFERENCES_PARSEDEXT")) ); - Gtk::VBox* vbre = Gtk::manage( new Gtk::VBox () ); - vbre->set_border_width (4); - Gtk::HBox* hb0 = Gtk::manage( new Gtk::HBox () ); - Gtk::Label* elab = Gtk::manage( new Gtk::Label (M("PREFERENCES_PARSEDEXTADD")+":") ); - hb0->pack_start (*elab, Gtk::PACK_SHRINK, 4); - extension = Gtk::manage( new Gtk::Entry () ); - extension->set_width_chars(5); - hb0->pack_start (*extension); - addExt = Gtk::manage( new Gtk::Button () ); - delExt = Gtk::manage( new Gtk::Button () ); - addExt->set_tooltip_text (M("PREFERENCES_PARSEDEXTADDHINT")); - delExt->set_tooltip_text (M("PREFERENCES_PARSEDEXTDELHINT")); - Gtk::Image* addExtImg = Gtk::manage( new RTImage ("list-add-small.png") ); - Gtk::Image* delExtImg = Gtk::manage( new RTImage ("list-remove-red-small.png") ); - addExt->add (*addExtImg); - delExt->add (*delExtImg); - hb0->pack_end (*delExt, Gtk::PACK_SHRINK, 4); - hb0->pack_end (*addExt, Gtk::PACK_SHRINK, 4); - extensions = Gtk::manage( new Gtk::TreeView () ); - Gtk::ScrolledWindow* hscrollw = Gtk::manage( new Gtk::ScrolledWindow () ); - hscrollw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); - hscrollw->add (*extensions); - extensionModel = Gtk::ListStore::create (extensionColumns); - extensions->set_model (extensionModel); - extensions->append_column_editable("Enabled", extensionColumns.enabled); - extensions->append_column("Extension", extensionColumns.ext); - extensions->set_headers_visible (false); - vbre->pack_start (*hscrollw); - vbre->pack_start (*hb0, Gtk::PACK_SHRINK, 4); - - fre->add (*vbre); - - Gtk::Frame* frc = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CACHEOPTS")) ); - Gtk::VBox* vbc = Gtk::manage( new Gtk::VBox () ); - frc->add (*vbc); - vbc->set_border_width (4); - - Gtk::HBox* hb3 = Gtk::manage( new Gtk::HBox () ); - Gtk::Label* chlab = Gtk::manage( new Gtk::Label (M("PREFERENCES_CACHETHUMBHEIGHT")+":") ); - maxThumbSize = Gtk::manage( new Gtk::SpinButton () ); - hb3->pack_start (*chlab, Gtk::PACK_SHRINK, 4); - hb3->pack_start (*maxThumbSize, Gtk::PACK_SHRINK, 4); - - maxThumbSize->set_digits (0); - maxThumbSize->set_increments (1, 10); - maxThumbSize->set_range (40, 800); - vbc->pack_start (*hb3, Gtk::PACK_SHRINK, 4); - - Gtk::HBox* hb4 = Gtk::manage( new Gtk::HBox () ); - Gtk::Label* celab = Gtk::manage( new Gtk::Label (M("PREFERENCES_CACHEMAXENTRIES")+":") ); - maxCacheEntries = Gtk::manage( new Gtk::SpinButton () ); - hb4->pack_start (*celab, Gtk::PACK_SHRINK, 4); - hb4->pack_start (*maxCacheEntries, Gtk::PACK_SHRINK, 4); - - maxCacheEntries->set_digits (0); - maxCacheEntries->set_increments (1, 10); - maxCacheEntries->set_range (10, 100000); - vbc->pack_start (*hb4, Gtk::PACK_SHRINK, 4); - - Gtk::HBox* hb5 = Gtk::manage( new Gtk::HBox () ); - clearThumbnails = Gtk::manage( new Gtk::Button (M("PREFERENCES_CACHECLEARTHUMBS")) ); - clearProfiles = Gtk::manage( new Gtk::Button (M("PREFERENCES_CACHECLEARPROFILES")) ); - clearAll = Gtk::manage( new Gtk::Button (M("PREFERENCES_CACHECLEARALL")) ); - hb5->pack_start (*clearThumbnails, Gtk::PACK_SHRINK, 4); - hb5->pack_start (*clearProfiles, Gtk::PACK_SHRINK, 4); - hb5->pack_start (*clearAll, Gtk::PACK_SHRINK, 4); - vbc->pack_start (*hb5, Gtk::PACK_SHRINK, 4); - - Gtk::HBox* hb6 = Gtk::manage( new Gtk::HBox () ); - Gtk::VBox* vb6 = Gtk::manage( new Gtk::VBox () ); - - vb6->pack_start (*fro); - vb6->pack_start (*frmnu); - vb6->pack_end (*frc); - hb6->pack_start (*vb6); - hb6->pack_start (*fre); - hb6->set_spacing(4); - - mvbfb->pack_start (*hb6, Gtk::PACK_SHRINK, 4); - -// mvbfb->pack_start (*fro, Gtk::PACK_SHRINK, 4); -// mvbfb->pack_start (*fre); -// mvbfb->pack_start (*frc, Gtk::PACK_SHRINK, 4); - - addExt->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::addExtPressed) ); - delExt->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::delExtPressed) ); - extension->signal_activate().connect( sigc::mem_fun(*this, &Preferences::addExtPressed) ); - clearThumbnails->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::clearThumbImagesPressed) ); - clearProfiles->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::clearProfilesPressed) ); - clearAll->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::clearAllPressed) ); - - return mvbfb; -} - -Gtk::Widget* Preferences::getSoundPanel () { - Gtk::VBox* pSnd = new Gtk::VBox (); - - ckbSndEnable = Gtk::manage( new Gtk::CheckButton (M("GENERAL_ENABLE"))); - sndEnableConn = ckbSndEnable->signal_toggled().connect (sigc::mem_fun(*this, &Preferences::sndEnableToggled)); - - pSnd->pack_start (*ckbSndEnable, Gtk::PACK_SHRINK, 4); - - Gtk::HBox* hblSndHelp = Gtk::manage (new Gtk::HBox ()); - Gtk::Label* lSndHelp = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_HELP"))); - hblSndHelp->pack_start (*lSndHelp, Gtk::PACK_SHRINK, 4); - pSnd->pack_start (*hblSndHelp, Gtk::PACK_SHRINK, 4); - - // BatchQueueDone - Gtk::HBox* pBatchQueueDone = Gtk::manage( new Gtk::HBox() ); - - Gtk::Label* lSndBatchQueueDone = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_BATCHQUEUEDONE") + Glib::ustring(":"))); - pBatchQueueDone->pack_start (*lSndBatchQueueDone, Gtk::PACK_SHRINK, 4); - - txtSndBatchQueueDone = Gtk::manage (new Gtk::Entry()); - pBatchQueueDone->pack_end (*txtSndBatchQueueDone, Gtk::PACK_EXPAND_WIDGET, 4); - - pSnd->pack_start (*pBatchQueueDone, Gtk::PACK_SHRINK, 4); - - // LngEditProcDone - Gtk::HBox* pSndLngEditProcDone = Gtk::manage( new Gtk::HBox() ); - - Gtk::Label* lSndLngEditProcDone = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_LNGEDITPROCDONE") + Glib::ustring(":"))); - pSndLngEditProcDone->pack_start (*lSndLngEditProcDone, Gtk::PACK_SHRINK, 4); - - txtSndLngEditProcDone = Gtk::manage (new Gtk::Entry()); - pSndLngEditProcDone->pack_start (*txtSndLngEditProcDone, Gtk::PACK_EXPAND_WIDGET, 4); - - Gtk::Label* lSndLngEditProcDoneSecs = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_TRESHOLDSECS") + Glib::ustring(":"))); - pSndLngEditProcDone->pack_start (*lSndLngEditProcDoneSecs, Gtk::PACK_SHRINK, 12); - - spbSndLngEditProcDoneSecs = Gtk::manage( new Gtk::SpinButton () ); - spbSndLngEditProcDoneSecs->set_digits (1); - spbSndLngEditProcDoneSecs->set_increments (0.5, 1); - spbSndLngEditProcDoneSecs->set_range (0, 10); - pSndLngEditProcDone->pack_end (*spbSndLngEditProcDoneSecs, Gtk::PACK_SHRINK, 4); - - pSnd->pack_start (*pSndLngEditProcDone, Gtk::PACK_SHRINK, 4); - - pSnd->set_border_width (4); - - sndEnableToggled(); - - return pSnd; -} - -void Preferences::parseDir (Glib::ustring dirname, std::vector& items, Glib::ustring ext) { - - if (dirname.empty()) - return; - - // process directory - Glib::Dir* dir = NULL; - try { - dir = new Glib::Dir (dirname); - } - catch (const Glib::Error& e) { - return; - } - for (Glib::DirIterator i = dir->begin(); i!=dir->end(); ++i) { - Glib::ustring fname = Glib::build_filename(dirname, *i); - Glib::ustring sname = *i; - // ignore directories - if (!safe_file_test (fname, Glib::FILE_TEST_IS_DIR) && sname.size() >= ext.size() && sname.substr (sname.size()-ext.size(), ext.size()).casefold() == ext) - items.push_back (sname.substr(0,sname.size()-ext.size())); - } - std::sort(items.begin(), items.end()); - delete dir; -} - -void Preferences::storePreferences () { - - // With the new mechanism, we can't be sure of the availability of the DEFPROFILE_RAW & DEFPROFILE_IMG profiles, - // because useBundledProfiles may be false. We're now using DEFPROFILE_INTERNAL instead, which is always available. - moptions.defProfRaw = rprofiles->getFullPathFromActiveRow(); - if (moptions.defProfRaw.empty()) moptions.defProfRaw = DEFPROFILE_INTERNAL; - moptions.defProfImg = iprofiles->getFullPathFromActiveRow(); - if (moptions.defProfImg.empty()) moptions.defProfImg = DEFPROFILE_INTERNAL; - - moptions.dateFormat = dateformat->get_text(); - moptions.panAccelFactor = (int)panFactor->get_value(); - moptions.rememberZoomAndPan = rememberZoomPanCheckbutton->get_active(); - moptions.fbShowDateTime = showDateTime->get_active (); - moptions.fbShowBasicExif = showBasicExif->get_active (); - moptions.fbShowExpComp = showExpComp->get_active (); - moptions.menuGroupRank = ckbmenuGroupRank->get_active(); - moptions.menuGroupLabel = ckbmenuGroupLabel->get_active(); - moptions.menuGroupFileOperations = ckbmenuGroupFileOperations->get_active(); - moptions.menuGroupProfileOperations = ckbmenuGroupProfileOperations->get_active(); - moptions.menuGroupExtProg = ckbmenuGroupExtProg->get_active(); - moptions.highlightThreshold = (int)hlThresh->get_value (); - moptions.shadowThreshold = (int)shThresh->get_value (); - moptions.language = languages->get_active_text (); - moptions.languageAutoDetect = ckbLangAutoDetect->get_active (); - moptions.theme = theme->get_active_text (); - moptions.slimUI = slimUI->get_active (); - moptions.useSystemTheme = chUseSystemTheme->get_active (); - - Gdk::Color cropCol=butCropCol->get_color(); - moptions.cutOverlayBrush[0]=cropCol.get_red_p(); - moptions.cutOverlayBrush[1]=cropCol.get_green_p(); - moptions.cutOverlayBrush[2]=cropCol.get_blue_p(); - moptions.cutOverlayBrush[3]=butCropCol->get_alpha()/65535.0; - - Gdk::Color NavGuideCol=butNavGuideCol->get_color(); - moptions.navGuideBrush[0]=NavGuideCol.get_red_p(); - moptions.navGuideBrush[1]=NavGuideCol.get_green_p(); - moptions.navGuideBrush[2]=NavGuideCol.get_blue_p(); - moptions.navGuideBrush[3]=butNavGuideCol->get_alpha()/65535.0; - - moptions.font = fontbutton->get_font_name(); -#ifdef WIN32 - moptions.gimpDir = gimpDir->get_filename (); - moptions.psDir = psDir->get_filename (); -#elif defined __APPLE__ - moptions.psDir = psDir->get_filename (); -#endif - moptions.customEditorProg = editorToSendTo->get_text (); - if (edGimp->get_active ()) - moptions.editorToSendTo = 1; -#ifdef WIN32 - else if (edPS->get_active ()) - moptions.editorToSendTo = 2; -#elif defined __APPLE__ - else if (edPS->get_active ()) - moptions.editorToSendTo = 2; -#endif - else if (edOther->get_active ()) - moptions.editorToSendTo = 3; - - moptions.CPBPath = txtCustProfBuilderPath->get_text(); - moptions.CPBKeys = CPBKeyType(custProfBuilderLabelType->get_active_row_number()); - - moptions.rtSettings.monitorProfile = monProfile->get_filename (); -#if defined(WIN32) - moptions.rtSettings.autoMonitorProfile = cbAutoMonProfile->get_active (); -#endif - moptions.rtSettings.iccDirectory = iccDir->get_filename (); - moptions.rtSettings.colorimetricIntent = intent->get_active_row_number (); - moptions.rtSettings.viewingdevice = view->get_active_row_number (); - moptions.rtSettings.viewingdevicegrey = grey->get_active_row_number (); - moptions.rtSettings.viewinggreySc = greySc->get_active_row_number (); - // moptions.rtSettings.autocielab = cbAutocielab->get_active (); - moptions.rtSettings.ciecamfloat = cbciecamfloat->get_active (); - moptions.rtSettings.HistogramWorking = ckbHistogramWorking->get_active (); - moptions.rtSettings.leveldnv = dnv->get_active_row_number (); - moptions.rtSettings.leveldnti = dnti->get_active_row_number (); - moptions.rtSettings.leveldnliss = dnliss->get_active_row_number (); - moptions.rtSettings.leveldnaut = dnaut->get_active_row_number (); - moptions.rtSettings.nrwavlevel = dnwavlev->get_active_row_number (); - moptions.rtSettings.leveldnautsimpl = dnautsimpl->get_active_row_number (); - moptions.rtSettings.daubech = cbdaubech->get_active (); - - moptions.prevdemo = (prevdemo_t)cprevdemo->get_active_row_number (); - moptions.serializeTiffRead = ctiffserialize->get_active(); - if (sdcurrent->get_active ()) - moptions.startupDir = STARTUPDIR_CURRENT; - else if (sdhome->get_active ()) - moptions.startupDir = STARTUPDIR_HOME; - else if (sdlast->get_active ()) - moptions.startupDir = STARTUPDIR_LAST; - else if (sdother->get_active ()) { - moptions.startupDir = STARTUPDIR_CUSTOM; - moptions.startupPath = startupdir->get_text(); - } - - moptions.parseExtensions.clear (); - moptions.parseExtensionsEnabled.clear (); - Gtk::TreeNodeChildren c = extensionModel->children (); - for (size_t i=0; iget_value(); - moptions.maxThumbnailHeight = (int)maxThumbSize->get_value (); - moptions.maxCacheEntries = (int)maxCacheEntries->get_value (); - moptions.overlayedFileNames = overlayedFileNames->get_active (); - moptions.filmStripOverlayedFileNames = filmStripOverlayedFileNames->get_active(); - moptions.sameThumbSize = sameThumbSize->get_active(); - moptions.internalThumbIfUntouched = ckbInternalThumbIfUntouched->get_active (); - - moptions.saveParamsFile = saveParamsFile->get_active (); - moptions.saveParamsCache = saveParamsCache->get_active (); - moptions.paramsLoadLocation = (PPLoadLocation)loadParamsPreference->get_active_row_number (); - moptions.useBundledProfiles = useBundledProfiles->get_active (); - - moptions.tunnelMetaData = ckbTunnelMetaData->get_active (); - - moptions.rtSettings.darkFramesPath = darkFrameDir->get_filename(); - moptions.rtSettings.flatFieldsPath = flatFieldDir->get_filename(); - - moptions.clutsDir = clutsDir->get_filename(); - - moptions.baBehav.resize (ADDSET_PARAM_NUM); - for (Gtk::TreeIter sections=behModel->children().begin(); sections!=behModel->children().end(); sections++) - for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) - moptions.baBehav[adjs->get_value (behavColumns.addsetid)] = adjs->get_value (behavColumns.badd); - - int editorMode=editorLayout->get_active_row_number(); - moptions.tabbedUI = (editorMode>1); - moptions.multiDisplayMode = editorMode==3 ? 1:0; - moptions.mainNBVertical = editorMode==1; - - moptions.curvebboxpos = curveBBoxPosC->get_active_row_number(); - moptions.histogramPosition = ckbHistogramPositionLeft->get_active() ? 1 : 2; - moptions.FileBrowserToolbarSingleRow = ckbFileBrowserToolbarSingleRow->get_active(); - moptions.showFilmStripToolBar = ckbShowFilmStripToolBar->get_active(); - moptions.hideTPVScrollbar = ckbHideTPVScrollbar->get_active(); - moptions.overwriteOutputFile = chOverwriteOutputFile->get_active (); - moptions.UseIconNoText = ckbUseIconNoText->get_active(); - - moptions.rgbDenoiseThreadLimit = rgbDenoiseTreadLimitSB->get_value_as_int(); - moptions.clutCacheSize = clutCacheSizeSB->get_value_as_int(); - moptions.maxInspectorBuffers = maxInspectorBuffersSB->get_value_as_int(); - - // Sounds only on Windows and Linux -#if defined(WIN32) || defined(__linux__) - moptions.sndEnable = ckbSndEnable->get_active (); - moptions.sndBatchQueueDone = txtSndBatchQueueDone->get_text (); - moptions.sndLngEditProcDone = txtSndLngEditProcDone->get_text (); - moptions.sndLngEditProcDoneSecs = spbSndLngEditProcDoneSecs->get_value (); -#endif -} - -void Preferences::fillPreferences () { - - tconn.block (true); - sconn.block (true); - dfconn.block (true); - ffconn.block (true); - rpconn.block(true); - ipconn.block(true); - bpconn.block(true); - - rprofiles->setActiveRowFromFullPath (moptions.defProfRaw); - forRAWComboChanged(); // update the tooltip - iprofiles->setActiveRowFromFullPath (moptions.defProfImg); - forImageComboChanged(); // update the tooltip - dateformat->set_text (moptions.dateFormat); - panFactor->set_value (moptions.panAccelFactor); - rememberZoomPanCheckbutton->set_active (moptions.rememberZoomAndPan); - ctiffserialize->set_active(moptions.serializeTiffRead); -#if !defined(__APPLE__) // monitor profile not supported on apple - if (safe_file_test (moptions.rtSettings.monitorProfile, Glib::FILE_TEST_EXISTS)) - monProfile->set_filename (moptions.rtSettings.monitorProfile); - if (moptions.rtSettings.monitorProfile.empty()) - monProfile->set_current_folder (moptions.rtSettings.iccDirectory); -#if defined(WIN32) - cbAutoMonProfile->set_active(moptions.rtSettings.autoMonitorProfile); -#endif -#endif - - if (Glib::file_test (moptions.rtSettings.iccDirectory, Glib::FILE_TEST_IS_DIR)) - iccDir->set_current_folder (moptions.rtSettings.iccDirectory); - intent->set_active (moptions.rtSettings.colorimetricIntent); - view->set_active (moptions.rtSettings.viewingdevice); - grey->set_active (moptions.rtSettings.viewingdevicegrey); - greySc->set_active (moptions.rtSettings.viewinggreySc); - dnv->set_active (moptions.rtSettings.leveldnv); - dnti->set_active (moptions.rtSettings.leveldnti); - dnliss->set_active (moptions.rtSettings.leveldnliss); - dnaut->set_active (moptions.rtSettings.leveldnaut); - dnautsimpl->set_active (moptions.rtSettings.leveldnautsimpl); - dnwavlev->set_active (moptions.rtSettings.nrwavlevel); - cprevdemo->set_active (moptions.prevdemo); - cbdaubech->set_active (moptions.rtSettings.daubech); - -// cbAutocielab->set_active (moptions.rtSettings.autocielab); - cbciecamfloat->set_active (moptions.rtSettings.ciecamfloat); - ckbHistogramWorking->set_active (moptions.rtSettings.HistogramWorking); - languages->set_active_text (moptions.language); - ckbLangAutoDetect->set_active (moptions.languageAutoDetect); - theme->set_active_text (moptions.theme); - slimUI->set_active(moptions.slimUI); - chUseSystemTheme->set_active(moptions.useSystemTheme); - - Gdk::Color cropCol; - cropCol.set_rgb_p(moptions.cutOverlayBrush[0],moptions.cutOverlayBrush[1],moptions.cutOverlayBrush[2]); - butCropCol->set_color(cropCol); - butCropCol->set_alpha ( (unsigned short)(moptions.cutOverlayBrush[3]*65535.0)); - - Gdk::Color NavGuideCol; - NavGuideCol.set_rgb_p(moptions.navGuideBrush[0],moptions.navGuideBrush[1],moptions.navGuideBrush[2]); - butNavGuideCol->set_color(NavGuideCol); - butNavGuideCol->set_alpha ( (unsigned short)(moptions.navGuideBrush[3]*65535.0)); - - fontbutton->set_font_name(moptions.font); - showDateTime->set_active (moptions.fbShowDateTime); - showBasicExif->set_active (moptions.fbShowBasicExif); - showExpComp->set_active (moptions.fbShowExpComp); - ckbmenuGroupRank->set_active(moptions.menuGroupRank); - ckbmenuGroupLabel->set_active(moptions.menuGroupLabel); - ckbmenuGroupFileOperations->set_active(moptions.menuGroupFileOperations); - ckbmenuGroupProfileOperations->set_active(moptions.menuGroupProfileOperations); - ckbmenuGroupExtProg->set_active(moptions.menuGroupExtProg); - - hlThresh->set_value (moptions.highlightThreshold); - shThresh->set_value (moptions.shadowThreshold); - - edGimp->set_active (moptions.editorToSendTo==1); - edOther->set_active (moptions.editorToSendTo==3); -#ifdef WIN32 - edPS->set_active (moptions.editorToSendTo==2); - if (safe_file_test (moptions.gimpDir, Glib::FILE_TEST_IS_DIR)) - gimpDir->set_current_folder (moptions.gimpDir); - if (safe_file_test (moptions.psDir, Glib::FILE_TEST_IS_DIR)) - psDir->set_current_folder (moptions.psDir); -#elif defined __APPLE__ - edPS->set_active (moptions.editorToSendTo==2); - if (safe_file_test (moptions.psDir, Glib::FILE_TEST_IS_DIR)) - psDir->set_current_folder (moptions.psDir); -#endif - editorToSendTo->set_text (moptions.customEditorProg); - - txtCustProfBuilderPath->set_text(moptions.CPBPath); - custProfBuilderLabelType->set_active(moptions.CPBKeys); - - - if (moptions.startupDir==STARTUPDIR_CURRENT) - sdcurrent->set_active (); - else if (moptions.startupDir==STARTUPDIR_LAST) - sdlast->set_active (); - else if (moptions.startupDir==STARTUPDIR_HOME) - sdhome->set_active (); - else if (moptions.startupDir==STARTUPDIR_CUSTOM) { - sdother->set_active (); - startupdir->set_text (moptions.startupPath); - } - - extensionModel->clear (); - for (size_t i=0; iappend()); - row[extensionColumns.enabled] = moptions.parseExtensionsEnabled[i]; - row[extensionColumns.ext] = moptions.parseExtensions[i]; - } - - maxThumbSize->set_value (moptions.maxThumbnailHeight); - maxRecentFolders->set_value(moptions.maxRecentFolders); - maxCacheEntries->set_value (moptions.maxCacheEntries); - overlayedFileNames->set_active (moptions.overlayedFileNames); - filmStripOverlayedFileNames->set_active(moptions.filmStripOverlayedFileNames); - sameThumbSize->set_active(moptions.sameThumbSize); - ckbInternalThumbIfUntouched->set_active(moptions.internalThumbIfUntouched); - - saveParamsFile->set_active (moptions.saveParamsFile); - saveParamsCache->set_active (moptions.saveParamsCache); - loadParamsPreference->set_active (moptions.paramsLoadLocation); - useBundledProfiles->set_active (moptions.useBundledProfiles); - - ckbTunnelMetaData->set_active (moptions.tunnelMetaData); - - if (!moptions.tabbedUI) - editorLayout->set_active(moptions.mainNBVertical ? 1 : 0); - else - editorLayout->set_active(moptions.multiDisplayMode ? 3 : 2); - - curveBBoxPosC->set_active(moptions.curvebboxpos); - ckbHistogramPositionLeft->set_active(moptions.histogramPosition==1); - // ckbHistogramWorking->set_active(moptions.histogramWorking==1); - ckbFileBrowserToolbarSingleRow->set_active(moptions.FileBrowserToolbarSingleRow); - ckbShowFilmStripToolBar->set_active(moptions.showFilmStripToolBar); - ckbHideTPVScrollbar->set_active(moptions.hideTPVScrollbar); - ckbUseIconNoText->set_active(moptions.UseIconNoText); - - rgbDenoiseTreadLimitSB->set_value(moptions.rgbDenoiseThreadLimit); - clutCacheSizeSB->set_value(moptions.clutCacheSize); - maxInspectorBuffersSB->set_value(moptions.maxInspectorBuffers); - - darkFrameDir->set_current_folder( moptions.rtSettings.darkFramesPath ); - darkFrameChanged (); - - flatFieldDir->set_current_folder( moptions.rtSettings.flatFieldsPath ); - flatFieldChanged (); - - clutsDir->set_current_folder( moptions.clutsDir ); - - addc.block (true); - setc.block (true); - if (moptions.baBehav.size() == ADDSET_PARAM_NUM) { - for (size_t i=0; ichildren().begin(); sections!=behModel->children().end(); sections++) - for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) - if (adjs->get_value (behavColumns.addsetid) == (int)i) { - adjs->set_value (behavColumns.badd, moptions.baBehav[i]==1); - adjs->set_value (behavColumns.bset, moptions.baBehav[i]!=1); - break; - } - } - addc.block (false); - setc.block (false); - tconn.block (false); - sconn.block (false); - dfconn.block (false); - ffconn.block (false); - rpconn.block(true); - ipconn.block(true); - bpconn.block(false); - - chOverwriteOutputFile->set_active (moptions.overwriteOutputFile); - - // Sounds only on Windows and Linux -#if defined(WIN32) || defined(__linux__) - ckbSndEnable->set_active (moptions.sndEnable); - txtSndBatchQueueDone->set_text (moptions.sndBatchQueueDone); - txtSndLngEditProcDone->set_text (moptions.sndLngEditProcDone); - spbSndLngEditProcDoneSecs->set_value (moptions.sndLngEditProcDoneSecs); -#endif -} - -/* -void Preferences::loadPressed () { - - moptions.copyFrom (&options); - fillPreferences (); -} - -void Preferences::savePressed () { - - storePreferences (); - options.copyFrom (&moptions); - Options::save (); -} -*/ - -#if defined(WIN32) -void Preferences::autoMonProfileToggled () { - monProfile->set_sensitive(!cbAutoMonProfile->get_active()); -} -#endif -/* -void Preferences::autocielabToggled () { -// cbAutocielab->set_sensitive(cbAutocielab->get_active()); -} -*/ -void Preferences::sndEnableToggled () { - txtSndBatchQueueDone->set_sensitive(ckbSndEnable->get_active()); - txtSndLngEditProcDone->set_sensitive(ckbSndEnable->get_active()); - spbSndLngEditProcDoneSecs->set_sensitive(ckbSndEnable->get_active()); -} - -void Preferences::langAutoDetectToggled () { - languages->set_sensitive(!ckbLangAutoDetect->get_active()); -} - -void Preferences::okPressed () { - - storePreferences (); - workflowUpdate(); - options.copyFrom (&moptions); - options.filterOutParsedExtensions(); - Options::save (); - hide (); -} - -void Preferences::cancelPressed () { - - bool currentSlimState = options.slimUI; - options.slimUI = oldSlimUI; - - // set the initial theme back - if (theme->get_active_text()!=options.theme || options.slimUI!=currentSlimState) { - RTImage::setPaths(options); - RTImage::updateImages(); - switchThemeTo(options.theme, options.slimUI); - } - - // set the initial font back - if (fontbutton->get_font_name() != options.font) - switchFontTo(options.font); - - // update the profileStore - if (useBundledProfiles->get_active () != options.useBundledProfiles) { - // we have to rescan with the old value; - bpconn.block(true); - useBundledProfiles->set_active (false); - bundledProfilesChanged(); - bpconn.block(false); - } - - hide (); -} - -void Preferences::selectStartupDir () { - - Gtk::FileChooserDialog dialog(M("PREFERENCES_DIRSELECTDLG"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); -// dialog.set_transient_for(*this); - - //Add response buttons the the dialog: - dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::StockID("gtk-open"), Gtk::RESPONSE_OK); - - int result = dialog.run(); - - if (result==Gtk::RESPONSE_OK) - startupdir->set_text (dialog.get_filename()); -} - -void Preferences::aboutPressed () { - - splash = new Splash (*this); - splash->set_transient_for (*this); - splash->signal_delete_event().connect( sigc::mem_fun(*this, &Preferences::splashClosed) ); - splash->show (); -} - -void Preferences::themeChanged () { - - moptions.theme = theme->get_active_text (); - moptions.useSystemTheme = chUseSystemTheme->get_active (); - RTImage::setPaths(moptions); - RTImage::updateImages(); - switchThemeTo(theme->get_active_text (), slimUI->get_active()); -} - -void Preferences::forRAWComboChanged () { - if (!rprofiles) - return; - const ProfileStoreEntry *selectedEntry = rprofiles->getSelectedEntry(); - if (!selectedEntry) - return; - - if (selectedEntry->type == PSET_FOLDER) { - rpconn.block(true); - rprofiles->set_active(currRawRow); - rpconn.block(false); - } - else - currRawRow = rprofiles->get_active(); - - rprofiles->set_tooltip_text(selectedEntry->label); -} - -void Preferences::forImageComboChanged () { - if (!iprofiles) - return; - const ProfileStoreEntry *selectedEntry = iprofiles->getSelectedEntry(); - if (!selectedEntry) - return; - - if (selectedEntry->type == PSET_FOLDER) { - ipconn.block(true); - iprofiles->set_active(currImgRow); - ipconn.block(false); - } - else - currImgRow = rprofiles->get_active(); - iprofiles->set_tooltip_text(iprofiles->getSelectedEntry()->label); -} - -void Preferences::layoutComboChanged () { - editorLayout->set_tooltip_text(editorLayout->get_active_text()); -} - -void Preferences::bundledProfilesChanged () { - rpconn.block (true); - ipconn.block (true); - - // parseProfiles does use options.useBundledProfiles, so we temporarily change its value - bool currValue = options.useBundledProfiles; - options.useBundledProfiles = useBundledProfiles->get_active (); - - // rescan the file's tree - profileStore.parseProfiles(); // This will call Preferences::updateProfileList in return - - // restoring back the old value - options.useBundledProfiles = currValue; - - ipconn.block (false); - rpconn.block (false); -} - -void Preferences::storeCurrentValue() { - // TODO: Find a way to get and restore the current selection; the following line can't work anymore - storedValueRaw = rprofiles->getFullPathFromActiveRow(); - storedValueImg = iprofiles->getFullPathFromActiveRow(); -} - -void Preferences::updateProfileList() { - rprofiles->updateProfileList(); - iprofiles->updateProfileList(); -} - -void Preferences::restoreValue() { - if (!rprofiles->setActiveRowFromFullPath(storedValueRaw)) { - moptions.defProfRaw = DEFPROFILE_INTERNAL; - rpconn.block(true); - rprofiles->setInternalEntry(); - rpconn.block(false); - } - currRawRow = rprofiles->get_active(); - - if (!iprofiles->setActiveRowFromFullPath(storedValueImg)) { - moptions.defProfImg = DEFPROFILE_INTERNAL; - ipconn.block(true); - iprofiles->setInternalEntry(); - ipconn.block(false); - } - currImgRow = iprofiles->get_active(); - - storedValueRaw = ""; - storedValueImg = ""; -} - -void Preferences::fontChanged () { - - switchFontTo(fontbutton->get_font_name()); -} - -void Preferences::switchThemeTo(Glib::ustring newTheme, bool slimInterface) { - - std::vector files; - files.push_back (argv0+"/themes/"+newTheme+".gtkrc"); - - options.slimUI = slimInterface; - - if (slimInterface) - files.push_back (argv0+"/themes/slim"); - Gtk::RC::set_default_files (files); - -#ifndef WIN32 - // For an unknown reason, gtkmm 2.22 don't know the gtk-button-images property, while it exists in the documentation... - // Anyway, the problem was Linux only - static Glib::RefPtr settings = Gtk::Settings::get_default(); - if (settings) - settings->property_gtk_button_images().set_value(true); - else - printf("Error: no default settings to update!\n"); -#endif - - Gtk::RC::reparse_all (Gtk::Settings::get_default()); - GdkEventClient event = { GDK_CLIENT_EVENT, NULL, TRUE, gdk_atom_intern("_GTK_READ_RCFILES", FALSE), 8 }; - gdk_event_send_clientmessage_toall ((GdkEvent*)&event); -} - -void Preferences::workflowUpdate (){ - - if(moptions.tabbedUI != options.tabbedUI) { - parent->MoveFileBrowserToMain(); - parent->CloseOpenEditors(); - parent->SetMainCurrent(); - if(moptions.tabbedUI){ - parent->epanel->hide_all(); - parent->set_title_decorated(""); - } - else{ - parent->epanel->show_all(); - parent->set_title_decorated(parent->epanel->getFileName()); - } - } - if(moptions.hideTPVScrollbar != options.hideTPVScrollbar) { - // Update the tool panels - parent->updateTPVScrollbar (moptions.hideTPVScrollbar); - } - if(moptions.UseIconNoText != options.UseIconNoText) { - // Update the tool's tab titles - parent->updateTabsUsesIcons(moptions.UseIconNoText); - } - if(moptions.FileBrowserToolbarSingleRow != options.FileBrowserToolbarSingleRow) { - // Update the position of the Query toolbar - parent->updateFBQueryTB(moptions.FileBrowserToolbarSingleRow); - } - if(moptions.showFilmStripToolBar != options.showFilmStripToolBar) { - // Update the visibility of FB toolbar - parent->updateFBToolBarVisibility(moptions.showFilmStripToolBar); - } - if(moptions.histogramPosition != options.histogramPosition) { - // Update the position of the Histogram - parent->updateHistogramPosition(options.histogramPosition, moptions.histogramPosition); - } - -} - -void Preferences::switchFontTo(Glib::ustring newFont) { - - Gtk::RC::parse_string (Glib::ustring::compose( - "style \"clearlooks-default\" { font_name = \"%1\" }", newFont)); - Gtk::RC::reparse_all (Gtk::Settings::get_default()); - GdkEventClient event = { GDK_CLIENT_EVENT, NULL, TRUE, gdk_atom_intern("_GTK_READ_RCFILES", FALSE), 8 }; - gdk_event_send_clientmessage_toall ((GdkEvent*)&event); -} - -void Preferences::useThemeChanged(){ - - if(!chUseSystemTheme->get_active()){ - hbtheme->set_sensitive(true); - fontbutton->set_sensitive(true); - } - else{ - hbtheme->set_sensitive(false); - fontbutton->set_sensitive(false); - } -} - -void Preferences::addExtPressed () { - - Gtk::TreeNodeChildren c = extensionModel->children (); - for (size_t i=0; iget_text ()) - return; - - Gtk::TreeRow row = *(extensionModel->append()); - - row[extensionColumns.enabled] = true; - row[extensionColumns.ext] = extension->get_text (); -} - -void Preferences::delExtPressed () { - - extensionModel->erase (extensions->get_selection()->get_selected ()); -} - -void Preferences::clearProfilesPressed () { - - cacheMgr->clearProfiles (); -} - -void Preferences::clearThumbImagesPressed () { - - cacheMgr->clearThumbImages (); -} - -void Preferences::clearAllPressed () { - - cacheMgr->clearAll (); -} - -void Preferences::darkFrameChanged () -{ - //Glib::ustring s(darkFrameDir->get_filename()); - Glib::ustring s(darkFrameDir->get_current_folder()); - //if( s.compare( rtengine::dfm.getPathname()) !=0 ){ - rtengine::dfm.init( s ); - updateDFinfos(); - //} -} - -void Preferences::flatFieldChanged () -{ - //Glib::ustring s(flatFieldDir->get_filename()); - Glib::ustring s(flatFieldDir->get_current_folder()); - //if( s.compare( rtengine::ffm.getPathname()) !=0 ){ - rtengine::ffm.init( s ); - updateFFinfos(); - //} -} - -void Preferences::updateDFinfos() -{ - int t1,t2; - rtengine::dfm.getStat(t1,t2); - Glib::ustring s = Glib::ustring::compose("%1: %2 %3, %4 %5", M("PREFERENCES_DARKFRAMEFOUND"), t1, M("PREFERENCES_DARKFRAMESHOTS"), t2, M("PREFERENCES_DARKFRAMETEMPLATES")); - dfLabel->set_text(s); -} - -void Preferences::updateFFinfos() -{ - int t1,t2; - rtengine::ffm.getStat(t1,t2); - Glib::ustring s = Glib::ustring::compose("%1: %2 %3, %4 %5", M("PREFERENCES_FLATFIELDFOUND"), t1, M("PREFERENCES_FLATFIELDSHOTS"), t2, M("PREFERENCES_FLATFIELDTEMPLATES")); - ffLabel->set_text(s); -} - -bool Preferences::splashClosed(GdkEventAny* event) { - delete splash; - splash = NULL; - return true; -} - -void Preferences::behAddAllPressed () { - - if (moptions.baBehav.size() == ADDSET_PARAM_NUM) { - for (size_t i=0; ichildren().begin(); sections!=behModel->children().end(); sections++) - for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) - if (adjs->get_value (behavColumns.addsetid) == (int)i) { - adjs->set_value (behavColumns.badd, true); - adjs->set_value (behavColumns.bset, false); - break; - } - } -} - -void Preferences::behSetAllPressed () { - - if (moptions.baBehav.size() == ADDSET_PARAM_NUM) { - for (size_t i=0; ichildren().begin(); sections!=behModel->children().end(); sections++) - for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) - if (adjs->get_value (behavColumns.addsetid) == (int)i) { - adjs->set_value (behavColumns.badd, false); - adjs->set_value (behavColumns.bset, true); - break; - } - } -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath , Oliver Duis + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include +#include "preferences.h" +#include "multilangmgr.h" +#include "splash.h" +#include "cachemanager.h" +#include "addsetids.h" +#include "../rtengine/dfmanager.h" +#include "../rtengine/ffmanager.h" +#include +#include "../rtengine/safegtk.h" +#include "rtimage.h" +#ifdef _OPENMP +#include +#endif + +extern Options options; +extern Glib::ustring argv0; + +Preferences::Preferences (RTWindow *rtwindow) : rprofiles(NULL), iprofiles(NULL), parent(rtwindow) { + + splash = NULL; + + set_title (M("MAIN_BUTTON_PREFERENCES")); + + moptions.copyFrom (&options); + oldSlimUI = options.slimUI; + + /* + * Do not increase height, since it's not visible on e.g. smaller netbook screens + * Default height is about 620 pixels actually, that's why we do not set the height anymore + * Netbook users will most certainly set a smaller font and use the "slimUI" mode, + * so they'll be able to shrink the pref window and close it. + */ + set_size_request (650, -1); + set_default_size (options.preferencesWidth, options.preferencesHeight); + set_border_width(4); + + Gtk::VBox* mainvb = get_vbox (); + mainvb->set_spacing(8); + set_has_separator (false); + + Gtk::Notebook* nb = Gtk::manage (new Gtk::Notebook ()); + mainvb->pack_start (*nb); + + Gtk::HBox* buttonpanel = Gtk::manage (new Gtk::HBox ()); + buttonpanel->set_spacing(8); + mainvb->pack_start (*buttonpanel, Gtk::PACK_SHRINK, 0); + + Gtk::Button* about = Gtk::manage (new Gtk::Button (M("GENERAL_ABOUT"))); + Gtk::Button* ok = Gtk::manage (new Gtk::Button (M("GENERAL_OK"))); + Gtk::Button* cancel = Gtk::manage (new Gtk::Button (M("GENERAL_CANCEL"))); + + about->set_image (*Gtk::manage(new RTImage ("rt-logo.png"))); + ok->set_image (*Gtk::manage(new RTImage ("gtk-apply.png"))); + cancel->set_image (*Gtk::manage(new RTImage ("gtk-cancel.png"))); + + + about->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::aboutPressed) ); + ok->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::okPressed) ); + cancel->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::cancelPressed) ); + + buttonpanel->pack_start (*about, Gtk::PACK_SHRINK, 0); + buttonpanel->pack_end (*ok, Gtk::PACK_SHRINK, 0); + buttonpanel->pack_end (*cancel, Gtk::PACK_SHRINK, 0); + nb->append_page (*getGeneralPanel(), M("PREFERENCES_TAB_GENERAL")); + nb->append_page (*getProcParamsPanel(), M("PREFERENCES_TAB_IMPROC")); + nb->append_page (*getFileBrowserPanel(), M("PREFERENCES_TAB_BROWSER")); + nb->append_page (*getColorManagementPanel(),M("PREFERENCES_TAB_COLORMGR")); + nb->append_page (*getBatchProcPanel(), M("PREFERENCES_BATCH_PROCESSING")); + nb->append_page (*getPerformancePanel(), M("PREFERENCES_TAB_PERFORMANCE")); + // Sounds only on Windows and Linux +#if defined(WIN32) || defined(__linux__) + nb->append_page (*getSoundPanel(), M("PREFERENCES_TAB_SOUND")); +#endif + nb->set_current_page (0); + + profileStore.addListener(this); + + fillPreferences (); + + show_all_children (); + set_modal (true); +} + + +Preferences::~Preferences () { + + profileStore.removeListener(this); + options.preferencesWidth = get_width(); + options.preferencesHeight = get_height(); +} + +Gtk::Widget* Preferences::getBatchProcPanel () { + + Gtk::VBox* mvbpp = Gtk::manage (new Gtk::VBox ()); + mvbpp->set_border_width(4); + + Gtk::ScrolledWindow* behscrollw = Gtk::manage (new Gtk::ScrolledWindow ()); + behscrollw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + behscrollw->set_border_width(8); + behscrollw->set_size_request(-1, 60); + Gtk::VBox* vbbeh = Gtk::manage( new Gtk::VBox () ); + vbbeh->pack_start (*behscrollw, Gtk::PACK_EXPAND_WIDGET); + Gtk::Frame* behFrame = Gtk::manage (new Gtk::Frame (M("PREFERENCES_BEHAVIOR"))); + behFrame->add (*vbbeh); + //mvbpp->pack_start (*behFrame); + mvbpp->pack_start (*behFrame, Gtk::PACK_EXPAND_WIDGET, 4); + Gtk::TreeView* behTreeView = Gtk::manage (new Gtk::TreeView ()); + behscrollw->add (*behTreeView); + + behModel = Gtk::TreeStore::create (behavColumns); + behTreeView->set_model (behModel); + + behTreeView->append_column (M("PREFERENCES_PROPERTY"), behavColumns.label); + behTreeView->append_column_editable (M("PREFERENCES_ADD"), behavColumns.badd); + behTreeView->append_column_editable (M("PREFERENCES_SET"), behavColumns.bset); + + Gtk::CellRendererToggle* cr_add = static_cast (behTreeView->get_column (1)->get_first_cell_renderer()); + Gtk::CellRendererToggle* cr_set = static_cast (behTreeView->get_column (2)->get_first_cell_renderer()); + + cr_add->set_radio (true); + cr_add->set_property("xalign", 0.0f); + sigc::connection addc = cr_add->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::behAddRadioToggled)); + cr_set->set_radio (true); + cr_set->set_property("xalign", 0.0f); + sigc::connection setc = cr_set->signal_toggled().connect (sigc::mem_fun (*this, &Preferences::behSetRadioToggled)); + + behTreeView->get_column (1)->add_attribute (*cr_add, "visible", behavColumns.visible); + behTreeView->get_column (1)->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED); + behTreeView->get_column (1)->set_fixed_width (50); + behTreeView->get_column (2)->add_attribute (*cr_set, "visible", behavColumns.visible); + behTreeView->get_column (2)->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED); + behTreeView->get_column (2)->set_fixed_width (50); + + // fill model + Gtk::TreeModel::iterator mi, ci; + + /* + * The TRUE/FALSE values of appendBehavList are replaced by the one defined in options.cc, + */ + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_EXPOSURE_LABEL")); + appendBehavList (mi, M("TP_EXPOSURE_EXPCOMP"), ADDSET_TC_EXPCOMP, false); + appendBehavList (mi, M("TP_EXPOSURE_COMPRHIGHLIGHTS"), ADDSET_TC_HLCOMPAMOUNT, false); + appendBehavList (mi, M("TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD"), ADDSET_TC_HLCOMPTHRESH, false); + appendBehavList (mi, M("TP_EXPOSURE_BLACKLEVEL"), ADDSET_TC_BLACKLEVEL, false); + appendBehavList (mi, M("TP_EXPOSURE_COMPRSHADOWS"), ADDSET_TC_SHCOMP, false); + appendBehavList (mi, M("TP_EXPOSURE_BRIGHTNESS"), ADDSET_TC_BRIGHTNESS, false); + appendBehavList (mi, M("TP_EXPOSURE_CONTRAST"), ADDSET_TC_CONTRAST, false); + appendBehavList (mi, M("TP_EXPOSURE_SATURATION"), ADDSET_TC_SATURATION, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_SHADOWSHLIGHTS_LABEL")); + appendBehavList (mi, M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), ADDSET_SH_HIGHLIGHTS, false); + appendBehavList (mi, M("TP_SHADOWSHLIGHTS_SHADOWS"), ADDSET_SH_SHADOWS, false); + appendBehavList (mi, M("TP_SHADOWSHLIGHTS_LOCALCONTR"), ADDSET_SH_LOCALCONTRAST, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_LABCURVE_LABEL")); + appendBehavList (mi, M("TP_LABCURVE_BRIGHTNESS"), ADDSET_LC_BRIGHTNESS, false); + appendBehavList (mi, M("TP_LABCURVE_CONTRAST"), ADDSET_LC_CONTRAST, false); + appendBehavList (mi, M("TP_LABCURVE_CHROMATICITY"), ADDSET_LC_CHROMATICITY, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_SHARPENING_LABEL")); + appendBehavList (mi, M("TP_SHARPENING_AMOUNT"), ADDSET_SHARP_AMOUNT, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_SHARPENEDGE_LABEL")); + appendBehavList (mi, M("TP_SHARPENEDGE_PASSES"), ADDSET_SHARPENEDGE_PASS, false); + appendBehavList (mi, M("TP_SHARPENEDGE_AMOUNT"), ADDSET_SHARPENEDGE_AMOUNT, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_SHARPENMICRO_LABEL")); + appendBehavList (mi, M("TP_SHARPENMICRO_AMOUNT"), ADDSET_SHARPENMICRO_AMOUNT, false); + appendBehavList (mi, M("TP_SHARPENMICRO_UNIFORMITY"), ADDSET_SHARPENMICRO_UNIFORMITY, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_DIRPYRDENOISE_LABEL")); + // appendBehavList (mi, M("TP_DIRPYRDENOISE_LUMA")+", "+M("TP_DIRPYRDENOISE_CHROMA"), ADDSET_DIRPYRDN_CHLUM, true); + appendBehavList (mi, M("TP_DIRPYRDENOISE_LUMA"),ADDSET_DIRPYRDN_LUMA, true); + appendBehavList (mi, M("TP_DIRPYRDENOISE_LDETAIL"),ADDSET_DIRPYRDN_LUMDET, true); + appendBehavList (mi, M("TP_DIRPYRDENOISE_CHROMA"), ADDSET_DIRPYRDN_CHROMA, true); + appendBehavList (mi, M("TP_DIRPYRDENOISE_RED"), ADDSET_DIRPYRDN_CHROMARED, true); + appendBehavList (mi, M("TP_DIRPYRDENOISE_BLUE"), ADDSET_DIRPYRDN_CHROMABLUE, true); + appendBehavList (mi, M("TP_DIRPYRDENOISE_GAMMA"), ADDSET_DIRPYRDN_GAMMA, true); + appendBehavList (mi, M("TP_DIRPYRDENOISE_PASSES"), ADDSET_DIRPYRDN_PASSES, true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_WBALANCE_LABEL")); + appendBehavList (mi, M("TP_WBALANCE_TEMPERATURE"), ADDSET_WB_TEMPERATURE, true); + appendBehavList (mi, M("TP_WBALANCE_GREEN"), ADDSET_WB_GREEN, true); + appendBehavList (mi, M("TP_WBALANCE_EQBLUERED"), ADDSET_WB_EQUAL, true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_COLORAPP_LABEL")); + appendBehavList (mi, M("TP_COLORAPP_CIECAT_DEGREE"),ADDSET_CAT_DEGREE, true); + appendBehavList (mi, M("TP_COLORAPP_ADAPTSCENE"),ADDSET_CAT_ADAPTSCENE, true); + appendBehavList (mi, M("TP_COLORAPP_LIGHT"),ADDSET_CAT_LIGHT, true); + appendBehavList (mi, M("TP_COLORAPP_BRIGHT"),ADDSET_CAT_BRIGHT, true); + appendBehavList (mi, M("TP_COLORAPP_CHROMA"),ADDSET_CAT_CHROMA, true); + appendBehavList (mi, M("TP_COLORAPP_RSTPRO"),ADDSET_CAT_RSTPRO, true); + appendBehavList (mi, M("TP_COLORAPP_CONTRAST"),ADDSET_CAT_CONTRAST, true); + appendBehavList (mi, M("TP_COLORAPP_CONTRAST_Q"),ADDSET_CAT_CONTRAST_Q, true); + appendBehavList (mi, M("TP_COLORAPP_CHROMA_S"),ADDSET_CAT_CHROMA_S, true); + appendBehavList (mi, M("TP_COLORAPP_CHROMA_M"),ADDSET_CAT_CHROMA_M, true); + appendBehavList (mi, M("TP_COLORAPP_HUE"),ADDSET_CAT_HUE, true); + appendBehavList (mi, M("TP_COLORAPP_ADAPTVIEWING"),ADDSET_CAT_ADAPTVIEWING, true); + appendBehavList (mi, M("TP_COLORAPP_BADPIXSL"),ADDSET_CAT_BADPIX, true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_VIBRANCE_LABEL")); + appendBehavList (mi, M("TP_VIBRANCE_PASTELS"), ADDSET_VIBRANCE_PASTELS, false); + appendBehavList (mi, M("TP_VIBRANCE_SATURATED"), ADDSET_VIBRANCE_SATURATED, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_GAMMA_OUTPUT")); + appendBehavList (mi, M("TP_GAMMA_CURV"), ADDSET_FREE_OUPUT_GAMMA, false); + appendBehavList (mi, M("TP_GAMMA_SLOP"), ADDSET_FREE_OUTPUT_SLOPE, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_CHMIXER_LABEL")); + appendBehavList (mi, M("TP_CHMIXER_RED")+", "+M("TP_CHMIXER_GREEN")+", "+M("TP_CHMIXER_BLUE"), ADDSET_CHMIXER, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_BWMIX_LABEL")); + appendBehavList (mi, M("TP_BWMIX_MIXC"), ADDSET_BLACKWHITE_HUES, false); + appendBehavList (mi, M("TP_BWMIX_GAMMA"), ADDSET_BLACKWHITE_GAMMA, false); + + mi = behModel->append (); + mi->set_value( behavColumns.label, M("TP_FILMSIMULATION_LABEL") ); + appendBehavList( mi, M( "TP_FILMSIMULATION_STRENGTH" ), ADDSET_FILMSIMULATION_STRENGTH, true ); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_COLORTONING_LABEL")); + appendBehavList (mi, M("TP_COLORTONING_SPLITCOCO"),ADDSET_COLORTONING_SPLIT , true); + appendBehavList (mi, M("TP_COLORTONING_SATURATIONTHRESHOLD"),ADDSET_COLORTONING_SATTHRESHOLD , true); + appendBehavList (mi, M("TP_COLORTONING_SATURATEDOPACITY"),ADDSET_COLORTONING_SATOPACITY , true); + appendBehavList (mi, M("TP_COLORTONING_BALANCE"),ADDSET_COLORTONING_BALANCE , true); + appendBehavList (mi, M("TP_COLORTONING_STRENGTH"),ADDSET_COLORTONING_STRENGTH , true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_ROTATE_LABEL")); + appendBehavList (mi, M("TP_ROTATE_DEGREE"), ADDSET_ROTATE_DEGREE, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_DISTORTION_LABEL")); + appendBehavList (mi, M("TP_DISTORTION_AMOUNT"), ADDSET_DIST_AMOUNT, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_PERSPECTIVE_LABEL")); + appendBehavList (mi, M("TP_PERSPECTIVE_HORIZONTAL")+", "+M("TP_PERSPECTIVE_VERTICAL"), ADDSET_PERSPECTIVE, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_GRADIENT_LABEL")); + appendBehavList (mi, M("TP_GRADIENT_DEGREE"), ADDSET_GRADIENT_DEGREE, false); + appendBehavList (mi, M("TP_GRADIENT_FEATHER"), ADDSET_GRADIENT_FEATHER, false); + appendBehavList (mi, M("TP_GRADIENT_STRENGTH"), ADDSET_GRADIENT_STRENGTH, false); + appendBehavList (mi, M("TP_GRADIENT_CENTER_X")+", "+M("TP_GRADIENT_CENTER_Y"), ADDSET_GRADIENT_CENTER, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_PCVIGNETTE_LABEL")); + appendBehavList (mi, M("TP_PCVIGNETTE_STRENGTH"), ADDSET_PCVIGNETTE_STRENGTH, false); + appendBehavList (mi, M("TP_PCVIGNETTE_FEATHER"), ADDSET_PCVIGNETTE_FEATHER, false); + appendBehavList (mi, M("TP_PCVIGNETTE_ROUNDNESS"), ADDSET_PCVIGNETTE_ROUNDNESS, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_CACORRECTION_LABEL")); + appendBehavList (mi, M("TP_CACORRECTION_BLUE")+", "+M("TP_CACORRECTION_RED"), ADDSET_CA, true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_VIGNETTING_LABEL")); + appendBehavList (mi, M("TP_VIGNETTING_AMOUNT"), ADDSET_VIGN_AMOUNT, false); + appendBehavList (mi, M("TP_VIGNETTING_RADIUS"), ADDSET_VIGN_RADIUS, false); + appendBehavList (mi, M("TP_VIGNETTING_STRENGTH"), ADDSET_VIGN_STRENGTH, false); + appendBehavList (mi, M("TP_VIGNETTING_CENTER_X")+", "+M("TP_VIGNETTING_CENTER_Y"), ADDSET_VIGN_CENTER, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_DIRPYREQUALIZER_LABEL")); + appendBehavList (mi, M("TP_EXPOSURE_CONTRAST"), ADDSET_DIRPYREQ, true); + appendBehavList (mi, M("TP_DIRPYREQUALIZER_THRESHOLD"), ADDSET_DIRPYREQ_THRESHOLD, true); + appendBehavList (mi, M("TP_DIRPYREQUALIZER_SKIN"), ADDSET_DIRPYREQ_SKINPROTECT, true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_WAVELET_LABEL")); + appendBehavList (mi, M("TP_WAVELET_LEVELS"), ADDSET_WA_THRES, true); + // appendBehavList (mi, M("TP_WAVELET_CONTRAST"), ADDSET_WA, true); + appendBehavList (mi, M("TP_WAVELET_THRESHOLD"), ADDSET_WA_THRESHOLD, true); + appendBehavList (mi, M("TP_WAVELET_THRESHOLD2"), ADDSET_WA_THRESHOLD2, true); + appendBehavList (mi, M("TP_WAVELET_CHRO"), ADDSET_WA_CHRO, true); + appendBehavList (mi, M("TP_WAVELET_CHR"), ADDSET_WA_CHROMA, true); + appendBehavList (mi, M("TP_WAVELET_SKIN"), ADDSET_WA_SKINPROTECT, true); + appendBehavList (mi, M("TP_WAVELET_EDRAD"), ADDSET_WA_EDGRAD, true); + appendBehavList (mi, M("TP_WAVELET_EDVAL"), ADDSET_WA_EDGVAL, true); + appendBehavList (mi, M("TP_WAVELET_RESCON"), ADDSET_WA_RESCON, true); + appendBehavList (mi, M("TP_WAVELET_THR"), ADDSET_WA_THRR, true); + appendBehavList (mi, M("TP_WAVELET_RESCONH"), ADDSET_WA_RESCONH, true); + appendBehavList (mi, M("TP_WAVELET_THRH"), ADDSET_WA_THRRH, true); + appendBehavList (mi, M("TP_WAVELET_RESCHRO"), ADDSET_WA_RESCHRO, true); + appendBehavList (mi, M("TP_WAVELET_TMSTRENGTH"), ADDSET_WA_TMRS, true); + appendBehavList (mi, M("TP_WAVELET_SKY"), ADDSET_WA_SKYPROTECT, true); + appendBehavList (mi, M("TP_WAVELET_CONTRA"), ADDSET_WA_CONTRAST, true); + appendBehavList (mi, M("TP_WAVELET_STRENGTH"), ADDSET_WA_STRENGTH, true); + appendBehavList (mi, M("TP_WAVELET_COMPGAMMA"), ADDSET_WA_GAMMA, true); + appendBehavList (mi, M("TP_WAVELET_EDGEDETECT"), ADDSET_WA_EDGEDETECT, true); + appendBehavList (mi, M("TP_WAVELET_EDGEDETECTTHR"), ADDSET_WA_EDGEDETECTTHR, true); + appendBehavList (mi, M("TP_WAVELET_EDGEDETECTTHR2"), ADDSET_WA_EDGEDETECTTHR2, true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_PREPROCESS_LABEL")); + appendBehavList (mi, M("TP_PREPROCESS_GREENEQUIL"), ADDSET_PREPROCESS_GREENEQUIL, false); + appendBehavList (mi, M("TP_PREPROCESS_LINEDENOISE"), ADDSET_PREPROCESS_LINEDENOISE, true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_EXPOS_WHITEPOINT_LABEL")); + appendBehavList (mi, M("TP_RAWEXPOS_LINEAR"), ADDSET_RAWEXPOS_LINEAR, false); + appendBehavList (mi, M("TP_RAWEXPOS_PRESER"), ADDSET_RAWEXPOS_PRESER, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_RAWEXPOS_BLACKS")); + appendBehavList (mi, M("TP_RAWEXPOS_RGB"), ADDSET_RAWEXPOS_BLACKS, false); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_FLATFIELD_LABEL")); + appendBehavList (mi, M("TP_FLATFIELD_CLIPCONTROL"), ADDSET_RAWFFCLIPCONTROL, true); + + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_CHROMATABERR_LABEL")); + appendBehavList (mi, M("TP_RAWCACORR_CARED")+", "+M("TP_RAWCACORR_CABLUE"), ADDSET_RAWCACORR, true); + + behTreeView->expand_all (); + + behAddAll = Gtk::manage( new Gtk::Button (M("PREFERENCES_BEHADDALL")) ); + behSetAll = Gtk::manage( new Gtk::Button (M("PREFERENCES_BEHSETALL")) ); + behAddAll->set_tooltip_markup (M("PREFERENCES_BEHADDALLHINT")); + behSetAll->set_tooltip_markup (M("PREFERENCES_BEHSETALLHINT")); + + behAddAll->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::behAddAllPressed) ); + behSetAll->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::behSetAllPressed) ); + + Gtk::HBox* buttonpanel1 = Gtk::manage (new Gtk::HBox ()); + //buttonpanel1->set_spacing(8); + buttonpanel1->pack_end (*behSetAll, Gtk::PACK_SHRINK, 4); + buttonpanel1->pack_end (*behAddAll, Gtk::PACK_SHRINK, 4); + vbbeh->pack_start (*buttonpanel1, Gtk::PACK_SHRINK, 4); + + chOverwriteOutputFile = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_OVERWRITEOUTPUTFILE")) ); + mvbpp->pack_start(*chOverwriteOutputFile, Gtk::PACK_SHRINK, 4); + + return mvbpp; +} + +void Preferences::appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, int id, bool set) { + + Gtk::TreeModel::iterator ci = behModel->append (parent->children()); + ci->set_value (behavColumns.label, label); + ci->set_value (behavColumns.visible, true); + ci->set_value (behavColumns.badd, !set); + ci->set_value (behavColumns.bset, set); + ci->set_value (behavColumns.addsetid, id); +} + +void Preferences::behAddRadioToggled (const Glib::ustring& path) { + + Gtk::TreeModel::iterator iter = behModel->get_iter (path); + //bool set = iter->get_value (behavColumns.bset); + iter->set_value (behavColumns.bset, false); + iter->set_value (behavColumns.badd, true); +} + +void Preferences::behSetRadioToggled (const Glib::ustring& path) { + + Gtk::TreeModel::iterator iter = behModel->get_iter (path); + //bool add = iter->get_value (behavColumns.badd); + iter->set_value (behavColumns.bset, true); + iter->set_value (behavColumns.badd, false); +} + +Gtk::Widget* Preferences::getProcParamsPanel () { + + Gtk::VBox* mvbpp = Gtk::manage (new Gtk::VBox ()); + + Gtk::Frame* fpp = Gtk::manage (new Gtk::Frame (M("PREFERENCES_IMPROCPARAMS"))); + Gtk::VBox* vbpp = Gtk::manage (new Gtk::VBox ()); + vbpp->set_border_width(4); + Gtk::Label* drlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_FORRAW")+":", Gtk::ALIGN_LEFT)); + rprofiles = Gtk::manage (new ProfileStoreComboBox ()); + rprofiles->set_size_request(50, -1); + rpconn = rprofiles->signal_changed().connect( sigc::mem_fun(*this, &Preferences::forRAWComboChanged) ); + Gtk::Label* drimg = Gtk::manage (new Gtk::Label (M("PREFERENCES_FORIMAGE")+":", Gtk::ALIGN_LEFT)); + iprofiles = Gtk::manage (new ProfileStoreComboBox ()); + iprofiles->set_size_request(50, -1); + ipconn = iprofiles->signal_changed().connect( sigc::mem_fun(*this, &Preferences::forImageComboChanged) ); + Gtk::Table* defpt = Gtk::manage (new Gtk::Table (2, 2)); + defpt->attach (*drlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + defpt->attach (*rprofiles, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + defpt->attach (*drimg, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); + defpt->attach (*iprofiles, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + vbpp->pack_start (*defpt, Gtk::PACK_SHRINK, 4); + useBundledProfiles = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_USEBUNDLEDPROFILES"))); + bpconn = useBundledProfiles->signal_clicked().connect ( sigc::mem_fun(*this, &Preferences::bundledProfilesChanged) ); + vbpp->pack_start (*useBundledProfiles, Gtk::PACK_SHRINK, 4); + fpp->add (*vbpp); + mvbpp->pack_start (*fpp, Gtk::PACK_SHRINK, 4); + + // Custom profile builder box + Gtk::Frame* cpfrm = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CUSTPROFBUILD")) ); + Gtk::Label* cplab = Gtk::manage( new Gtk::Label (M("PREFERENCES_CUSTPROFBUILDPATH")+":", Gtk::ALIGN_LEFT) ); + txtCustProfBuilderPath = Gtk::manage( new Gtk::Entry () ); + txtCustProfBuilderPath->set_tooltip_markup (M("PREFERENCES_CUSTPROFBUILDHINT")); + Gtk::Label* cpltypelab = Gtk::manage( new Gtk::Label (M("PREFERENCES_CUSTPROFBUILDKEYFORMAT")+":", Gtk::ALIGN_LEFT) ); + custProfBuilderLabelType = Gtk::manage (new Gtk::ComboBoxText ()); + custProfBuilderLabelType->append_text (M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_TID")); + custProfBuilderLabelType->append_text (M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_NAME")); + custProfBuilderLabelType->append_text (M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_TID") + "_" + M("PREFERENCES_CUSTPROFBUILDKEYFORMAT_NAME")); + Gtk::Table* cpbt = Gtk::manage (new Gtk::Table (2, 2)); + cpbt->set_border_width(4); + cpbt->attach (*cplab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + cpbt->attach (*txtCustProfBuilderPath, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + cpbt->attach (*cpltypelab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); + cpbt->attach (*custProfBuilderLabelType, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + cpfrm->add (*cpbt); + mvbpp->pack_start (*cpfrm, Gtk::PACK_SHRINK, 4); + + Gtk::Frame* fdp = Gtk::manage (new Gtk::Frame (M("PREFERENCES_PROFILEHANDLING"))); + Gtk::VBox* vbdp = Gtk::manage (new Gtk::VBox ()); + vbdp->set_border_width (4); + saveParamsFile = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_PROFILESAVEINPUT"))); + vbdp->pack_start (*saveParamsFile, Gtk::PACK_SHRINK, 4); + saveParamsCache = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_PROFILESAVECACHE"))); + vbdp->pack_start (*saveParamsCache, Gtk::PACK_SHRINK, 4); + Gtk::Label* lplab = Gtk::manage (new Gtk::Label (M("PREFERENCES_PROFILELOADPR")+":")); + loadParamsPreference = Gtk::manage (new Gtk::ComboBoxText ()); + loadParamsPreference->append_text (M("PREFERENCES_PROFILEPRCACHE")); + loadParamsPreference->append_text (M("PREFERENCES_PROFILEPRFILE")); + Gtk::HBox* hb41 = Gtk::manage (new Gtk::HBox ()); + hb41->pack_start (*lplab, Gtk::PACK_SHRINK, 0); + hb41->pack_start (*loadParamsPreference, Gtk::PACK_EXPAND_WIDGET, 0); + hb41->set_spacing(4); + vbdp->pack_start (*hb41, Gtk::PACK_EXPAND_WIDGET, 4); + fdp->add (*vbdp); + mvbpp->pack_start (*fdp, Gtk::PACK_SHRINK, 4); + + Gtk::Frame* fdf = Gtk::manage (new Gtk::Frame (M("PREFERENCES_DARKFRAME")) ); + Gtk::HBox* hb42 = Gtk::manage (new Gtk::HBox ()); + darkFrameDir = Gtk::manage(new Gtk::FileChooserButton(M("PREFERENCES_DIRDARKFRAMES"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + Gtk::Label *dfLab = Gtk::manage(new Gtk::Label(M("PREFERENCES_DIRDARKFRAMES")+":")); + hb42->pack_start(*dfLab , Gtk::PACK_SHRINK, 4 ); + hb42->pack_start(*darkFrameDir, Gtk::PACK_EXPAND_WIDGET, 4); + dfLabel = Gtk::manage(new Gtk::Label("Found:")); + Gtk::VBox* vbdf = Gtk::manage (new Gtk::VBox ()); + vbdf->pack_start( *hb42, Gtk::PACK_SHRINK, 4); + vbdf->pack_start( *dfLabel, Gtk::PACK_SHRINK, 4 ); + fdf->add( *vbdf ); + mvbpp->pack_start ( *fdf , Gtk::PACK_SHRINK, 4); + mvbpp->set_border_width (4); + + //dfconn = darkFrameDir->signal_file_set().connect ( sigc::mem_fun(*this, &Preferences::darkFrameChanged), true); + dfconn = darkFrameDir->signal_current_folder_changed().connect ( sigc::mem_fun(*this, &Preferences::darkFrameChanged), true); + + // FLATFIELD + Gtk::Frame* fff = Gtk::manage (new Gtk::Frame (M("PREFERENCES_FLATFIELD")) ); + Gtk::HBox* hb43 = Gtk::manage (new Gtk::HBox ()); + flatFieldDir = Gtk::manage(new Gtk::FileChooserButton(M("PREFERENCES_FLATFIELDSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + Gtk::Label *ffLab = Gtk::manage(new Gtk::Label(M("PREFERENCES_FLATFIELDSDIR")+":")); + hb43->pack_start(*ffLab , Gtk::PACK_SHRINK, 4 ); + hb43->pack_start(*flatFieldDir); + ffLabel = Gtk::manage(new Gtk::Label("Found:")); + Gtk::VBox* vbff = Gtk::manage (new Gtk::VBox ()); + vbff->pack_start( *hb43, Gtk::PACK_SHRINK, 4); + vbff->pack_start( *ffLabel, Gtk::PACK_SHRINK, 4 ); + fff->add( *vbff ); + mvbpp->pack_start ( *fff , Gtk::PACK_SHRINK, 4); + mvbpp->set_border_width (4); + + //ffconn = flatFieldDir->signal_file_set().connect ( sigc::mem_fun(*this, &Preferences::flatFieldChanged), true); + ffconn = flatFieldDir->signal_current_folder_changed().connect ( sigc::mem_fun(*this, &Preferences::flatFieldChanged), true); + + //Cluts Dir + Gtk::Frame* clutsDirFrame = Gtk::manage (new Gtk::Frame (M("PREFERENCES_FILMSIMULATION")) ); + Gtk::HBox* clutsDirBox = Gtk::manage (new Gtk::HBox ()); + clutsDir = Gtk::manage(new Gtk::FileChooserButton(M("PREFERENCES_CLUTSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + Gtk::Label *clutsDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_CLUTSDIR") + ":")); + Gtk::Label* clutsRestartNeeded = Gtk::manage( new Gtk::Label (Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")") ); + clutsDirBox->pack_start( *clutsDirLabel, Gtk::PACK_SHRINK, 4 ); + clutsDirBox->pack_start( *clutsDir ); + clutsDirBox->pack_start( *clutsRestartNeeded, Gtk::PACK_SHRINK, 4 ); + clutsDirBox->set_border_width( 4 ); + clutsDirFrame->add( *clutsDirBox ); + mvbpp->pack_start( *clutsDirFrame, Gtk::PACK_SHRINK, 4 ); + + Gtk::Frame* fmd = Gtk::manage (new Gtk::Frame (M("PREFERENCES_METADATA"))); + Gtk::VBox* vbmd = Gtk::manage (new Gtk::VBox ()); + ckbTunnelMetaData = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_TUNNELMETADATA"))); + vbmd->pack_start (*ckbTunnelMetaData, Gtk::PACK_SHRINK, 4); + fmd->add (*vbmd); + mvbpp->pack_start (*fmd, Gtk::PACK_SHRINK, 4); + + return mvbpp; +} + +Gtk::Widget* Preferences::getPerformancePanel () { + Gtk::VBox* mainContainer = Gtk::manage( new Gtk::VBox () ); + mainContainer->set_border_width (4); + mainContainer->set_spacing(4); + + Gtk::Frame* fprevdemo = Gtk::manage (new Gtk::Frame (M("PREFERENCES_PREVDEMO"))); + Gtk::HBox* hbprevdemo = Gtk::manage (new Gtk::HBox (false, 4)); + Gtk::Label* lprevdemo = Gtk::manage (new Gtk::Label (M("PREFERENCES_PREVDEMO_LABEL"))); + cprevdemo = Gtk::manage (new Gtk::ComboBoxText ()); + cprevdemo->append_text (M("PREFERENCES_PREVDEMO_FAST")); + cprevdemo->append_text (M("PREFERENCES_PREVDEMO_SIDECAR")); + cprevdemo->set_active (1); + hbprevdemo->pack_start (*lprevdemo, Gtk::PACK_SHRINK); + hbprevdemo->pack_start (*cprevdemo); + fprevdemo->add (*hbprevdemo); + hbprevdemo->set_border_width(4); + mainContainer->pack_start (*fprevdemo, Gtk::PACK_SHRINK, 4); + + Gtk::Frame* ftiffserialize = Gtk::manage (new Gtk::Frame (M("PREFERENCES_SERIALIZE_TIFF_READ"))); + Gtk::HBox* htiffserialize = Gtk::manage (new Gtk::HBox (false, 4)); + ctiffserialize = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SERIALIZE_TIFF_READ_LABEL")) ); + ctiffserialize->set_tooltip_text(M("PREFERENCES_SERIALIZE_TIFF_READ_TOOLTIP")); + htiffserialize->pack_start (*ctiffserialize); + ftiffserialize->add (*htiffserialize); + htiffserialize->set_border_width(4); + mainContainer->pack_start (*ftiffserialize, Gtk::PACK_SHRINK, 4); + + Gtk::Frame* fclut = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CLUTSCACHE")) ); + Gtk::HBox* clutCacheSizeHB = Gtk::manage( new Gtk::HBox () ); + clutCacheSizeHB->set_border_width(4); + clutCacheSizeHB->set_spacing(4); + Gtk::Label* CLUTLl = Gtk::manage( new Gtk::Label (M("PREFERENCES_CLUTSCACHE_LABEL") + ":", Gtk::ALIGN_LEFT)); + clutCacheSizeSB = Gtk::manage( new Gtk::SpinButton () ); + clutCacheSizeSB->set_digits (0); + clutCacheSizeSB->set_increments (1, 5); + clutCacheSizeSB->set_max_length(2); // Will this be sufficient? :) +#ifdef _OPENMP + clutCacheSizeSB->set_range (1, 2*omp_get_num_procs()); +#else + clutCacheSizeSB->set_range (1, 8); +#endif + clutCacheSizeHB->pack_start (*CLUTLl, Gtk::PACK_SHRINK, 0); + clutCacheSizeHB->pack_end (*clutCacheSizeSB, Gtk::PACK_SHRINK, 0); + fclut->add (*clutCacheSizeHB); + mainContainer->pack_start (*fclut, Gtk::PACK_SHRINK, 4); + + Gtk::Frame* finspect = Gtk::manage( new Gtk::Frame (M("PREFERENCES_INSPECT_LABEL")) ); + Gtk::HBox* maxIBuffersHB = Gtk::manage( new Gtk::HBox () ); + maxIBuffersHB->set_border_width(4); + maxIBuffersHB->set_spacing(4); + maxIBuffersHB->set_tooltip_text(M("PREFERENCES_INSPECT_MAXBUFFERS_TOOLTIP")); + Gtk::Label* maxIBufferLbl = Gtk::manage( new Gtk::Label (M("PREFERENCES_INSPECT_MAXBUFFERS_LABEL") + ":", Gtk::ALIGN_LEFT)); + maxInspectorBuffersSB = Gtk::manage( new Gtk::SpinButton () ); + maxInspectorBuffersSB->set_digits (0); + maxInspectorBuffersSB->set_increments (1, 5); + maxInspectorBuffersSB->set_max_length(2); + maxInspectorBuffersSB->set_range (1, 12); // ... we have to set a limit, 12 seem to be enough even for systems with tons of RAM + maxIBuffersHB->pack_start (*maxIBufferLbl, Gtk::PACK_SHRINK, 0); + maxIBuffersHB->pack_end (*maxInspectorBuffersSB, Gtk::PACK_SHRINK, 0); + finspect->add(*maxIBuffersHB); + mainContainer->pack_start(*finspect, Gtk::PACK_SHRINK, 4); + + Gtk::Frame* fdenoise = Gtk::manage( new Gtk::Frame (M("PREFERENCES_NOISE")) ); + Gtk::VBox* vbdenoise = Gtk::manage( new Gtk::VBox (Gtk::PACK_SHRINK, 4) ); + vbdenoise->set_border_width (4); + + Gtk::Label* lreloadneeded2 = Gtk::manage (new Gtk::Label (M("PREFERENCES_IMG_RELOAD_NEEDED"), Gtk::ALIGN_LEFT)); + Gtk::HBox* threadLimitHB = Gtk::manage (new Gtk::HBox (Gtk::PACK_SHRINK, 4)); + threadLimitHB->set_tooltip_text(M("PREFERENCES_RGBDTL_TOOLTIP")); + Gtk::Label* RGBDTLl = Gtk::manage( new Gtk::Label (M("PREFERENCES_RGBDTL_LABEL") + ":", Gtk::ALIGN_LEFT)); + rgbDenoiseTreadLimitSB = Gtk::manage( new Gtk::SpinButton () ); + rgbDenoiseTreadLimitSB->set_digits (0); + rgbDenoiseTreadLimitSB->set_increments (1, 5); + rgbDenoiseTreadLimitSB->set_max_length(2); // Will this be sufficient? :) + int maxThreadNumber = 10; +#ifdef _OPENMP + maxThreadNumber = omp_get_max_threads(); +#endif + rgbDenoiseTreadLimitSB->set_range (0, maxThreadNumber); + threadLimitHB->pack_start (*RGBDTLl, Gtk::PACK_SHRINK, 2); + threadLimitHB->pack_end (*rgbDenoiseTreadLimitSB, Gtk::PACK_SHRINK, 2); + + Gtk::Label* dnlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_LEVDN")+":", Gtk::ALIGN_LEFT)); + Gtk::Label* dnautlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_LEVAUTDN")+":", Gtk::ALIGN_LEFT)); + Gtk::Label* dnautsimpllab = Gtk::manage (new Gtk::Label (M("PREFERENCES_SIMPLAUT")+":", Gtk::ALIGN_LEFT)); + Gtk::Label* dntilab = Gtk::manage (new Gtk::Label (M("PREFERENCES_TINB")+":", Gtk::ALIGN_LEFT)); + Gtk::Label* dnwavlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_WAVLEV")+":", Gtk::ALIGN_LEFT)); + Gtk::Label* dnlisslab = Gtk::manage (new Gtk::Label (M("PREFERENCES_LISS")+":", Gtk::ALIGN_LEFT)); + + dnv = Gtk::manage (new Gtk::ComboBoxText ()); + dnv->append_text (M("PREFERENCES_MIN")); + dnv->append_text (M("PREFERENCES_SMA")); + dnv->append_text (M("PREFERENCES_MED")); + dnv->append_text (M("PREFERENCES_MAX")); + dnaut = Gtk::manage (new Gtk::ComboBoxText ()); + dnaut->append_text (M("PREFERENCES_AUTLOW")); + dnaut->append_text (M("PREFERENCES_AUTSTD")); + + dnautsimpl = Gtk::manage (new Gtk::ComboBoxText ()); + dnautsimpl->append_text (M("PREFERENCES_STDAUT")); + dnautsimpl->append_text (M("PREFERENCES_EXPAUT")); + + dnliss = Gtk::manage (new Gtk::ComboBoxText ()); + dnliss->append_text (M("PREFERENCES_AUTLISVLOW"));//very low + dnliss->append_text (M("PREFERENCES_AUTLISLOW"));//low + dnliss->append_text (M("PREFERENCES_AUTLISSTD"));//med + dnliss->append_text (M("PREFERENCES_AUTLISMAX"));//max + + dnti = Gtk::manage (new Gtk::ComboBoxText ()); + dnti->append_text (M("PREFERENCES_TISTD")); + dnti->append_text (M("PREFERENCES_TIMAX")); + + dnwavlev = Gtk::manage (new Gtk::ComboBoxText ()); + dnwavlev->append_text (M("PREFERENCES_WLZER")); + dnwavlev->append_text (M("PREFERENCES_WLONE")); + dnwavlev->append_text (M("PREFERENCES_WLTWO")); + + Gtk::Table* colon = Gtk::manage (new Gtk::Table (6, 2)); + colon->attach (*dnlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + colon->attach (*dnv, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colon->attach (*dnautlab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); + colon->attach (*dnaut, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colon->attach (*dnautsimpllab, 0, 1, 2, 3, Gtk::FILL, Gtk::SHRINK, 2, 2); + colon->attach (*dnautsimpl, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colon->attach (*dnlisslab, 0, 1, 3, 4, Gtk::FILL, Gtk::SHRINK, 2, 2); + colon->attach (*dnliss, 1, 2, 3, 4, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colon->attach (*dntilab, 0, 1, 4, 5, Gtk::FILL, Gtk::SHRINK, 2, 2); + colon->attach (*dnti, 1, 2, 4, 5, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colon->attach (*dnwavlab, 0, 1, 5, 6, Gtk::FILL, Gtk::SHRINK, 2, 2); + colon->attach (*dnwavlev, 1, 2, 5, 6, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + + vbdenoise->pack_start (*lreloadneeded2, Gtk::PACK_SHRINK); + vbdenoise->pack_start (*colon, Gtk::PACK_SHRINK); + vbdenoise->pack_start(*threadLimitHB, Gtk::PACK_SHRINK); + // <--- To be hard-coded and removed once tested + cbdaubech = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_DAUB_LABEL"), Gtk::ALIGN_LEFT)); + cbdaubech->set_tooltip_markup (M("PREFERENCES_DAUB_TOOLTIP")); + // vbdenoise->pack_start (*cbdaubech, Gtk::PACK_SHRINK); + // ---> + fdenoise->add (*vbdenoise); + mainContainer->pack_start (*fdenoise, Gtk::PACK_SHRINK, 4); + + return mainContainer; +} + +Gtk::Widget* Preferences::getColorManagementPanel () { + + Gtk::VBox* mvbcm = Gtk::manage (new Gtk::VBox ()); + mvbcm->set_border_width (4); + + Gtk::Label* intlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_CMETRICINTENT")+":", Gtk::ALIGN_LEFT)); + intent = Gtk::manage (new Gtk::ComboBoxText ()); + intent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); + intent->append_text (M("PREFERENCES_INTENT_RELATIVE")); + intent->append_text (M("PREFERENCES_INTENT_SATURATION")); + intent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); + + iccDir = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_ICCDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + Gtk::Label* pdlabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_ICCDIR")+":", Gtk::ALIGN_LEFT)); + + Gtk::FileFilter monProfileFilter_colprof; + monProfileFilter_colprof.set_name(M("FILECHOOSER_FILTER_COLPROF")); + monProfileFilter_colprof.add_pattern("*.icc"); + monProfileFilter_colprof.add_pattern("*.ICC"); + monProfileFilter_colprof.add_pattern("*.icm"); + monProfileFilter_colprof.add_pattern("*.ICM"); + Gtk::FileFilter monProfileFilter_any; + monProfileFilter_any.set_name(M("FILECHOOSER_FILTER_ANY")); + monProfileFilter_any.add_pattern("*"); + + monProfile = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_MONITORICC"), Gtk::FILE_CHOOSER_ACTION_OPEN)); + monProfile->add_filter (monProfileFilter_colprof); + monProfile->add_filter (monProfileFilter_any); + Gtk::Label* mplabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONITORICC")+":", Gtk::ALIGN_LEFT)); + +#if defined(WIN32) // Auto-detection not implemented for Linux, see issue 851 + cbAutoMonProfile = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_AUTOMONPROFILE"))); + autoMonProfileConn = cbAutoMonProfile->signal_toggled().connect (sigc::mem_fun(*this, &Preferences::autoMonProfileToggled)); +#endif + + Gtk::Table* colt = Gtk::manage (new Gtk::Table (3, 2)); + colt->attach (*intlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*intent, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*pdlabel, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*iccDir, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); +#if !defined(__APPLE__) // monitor profile not supported on apple + colt->attach (*mplabel, 0, 1, 2, 3, Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*monProfile, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); +#if defined(WIN32) + colt->attach (*cbAutoMonProfile, 1, 2, 3, 4, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); +#endif +#endif + mvbcm->pack_start (*colt, Gtk::PACK_SHRINK, 4); + +#if defined(WIN32) + autoMonProfileToggled(); +#endif + + Gtk::VBox* vbdp = Gtk::manage (new Gtk::VBox ()); + vbdp->set_border_width (4); + Gtk::Label* viewlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_VIEW")+":", Gtk::ALIGN_LEFT)); + + view = Gtk::manage (new Gtk::ComboBoxText ()); + view->append_text (M("PREFERENCES_D50")); + view->append_text (M("PREFERENCES_D55")); + view->append_text (M("PREFERENCES_D60")); + view->append_text (M("PREFERENCES_D65")); + view->append_text (M("PREFERENCES_BLACKBODY")); + view->append_text (M("PREFERENCES_FLUOF2")); + view->append_text (M("PREFERENCES_FLUOF7")); + view->append_text (M("PREFERENCES_FLUOF11")); + + Gtk::Label* greylab = Gtk::manage (new Gtk::Label (M("PREFERENCES_GREY")+":", Gtk::ALIGN_LEFT)); + grey = Gtk::manage (new Gtk::ComboBoxText ()); + grey->append_text (M("PREFERENCES_GREY05")); + grey->append_text (M("PREFERENCES_GREY10")); + grey->append_text (M("PREFERENCES_GREY15")); + grey->append_text (M("PREFERENCES_GREY18")); + grey->append_text (M("PREFERENCES_GREY23")); + grey->append_text (M("PREFERENCES_GREY30")); + grey->append_text (M("PREFERENCES_GREY40")); + + Gtk::Label* greySclab = Gtk::manage (new Gtk::Label (M("PREFERENCES_GREYSC")+":", Gtk::ALIGN_LEFT)); + greySc = Gtk::manage (new Gtk::ComboBoxText ()); + greySc->append_text (M("PREFERENCES_GREYSCA")); + greySc->append_text (M("PREFERENCES_GREYSC18")); + + Gtk::Frame* fcielab = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CIEART_FRAME")) ); + Gtk::VBox* vbcielab = Gtk::manage( new Gtk::VBox () ); + vbcielab->set_border_width (4); + + Gtk::Label* lreloadneeded1 = Gtk::manage (new Gtk::Label (M("PREFERENCES_IMG_RELOAD_NEEDED"), Gtk::ALIGN_LEFT)); + Gtk::Table* colo = Gtk::manage (new Gtk::Table (4, 2)); + colo->attach (*viewlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + colo->attach (*view, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colo->attach (*greylab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); + colo->attach (*grey, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colo->attach (*greySclab, 0, 1, 2, 3, Gtk::FILL, Gtk::SHRINK, 2, 2); + colo->attach (*greySc, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + cbciecamfloat = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_CIEART_LABEL"))); + colo->attach (*cbciecamfloat, 0, 1, 3, 4, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + cbciecamfloat->set_tooltip_markup (M("PREFERENCES_CIEART_TOOLTIP")); + vbcielab->pack_start (*lreloadneeded1, Gtk::PACK_SHRINK, 4); + vbcielab->pack_start (*colo, Gtk::PACK_EXPAND_WIDGET, 4); + fcielab->add (*vbcielab); + + mvbcm->pack_start (*fcielab, Gtk::PACK_SHRINK, 4); + + return mvbcm; +} + +Gtk::Widget* Preferences::getGeneralPanel () { + + Gtk::VBox* mvbsd = Gtk::manage( new Gtk::VBox () ); + + Gtk::Frame* fworklflow = Gtk::manage (new Gtk::Frame (M("PREFERENCES_WORKFLOW"))); + Gtk::VBox* vbworkflow = Gtk::manage (new Gtk::VBox (false, 4)); + vbworkflow->set_border_width (4); + + Gtk::HBox* hbworkflow = Gtk::manage (new Gtk::HBox (false, 4)); + Gtk::Label* flayoutlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_EDITORLAYOUT")+":")); + editorLayout = Gtk::manage (new Gtk::ComboBoxText ()); + editorLayout->append_text (M("PREFERENCES_SINGLETAB")); + editorLayout->append_text (M("PREFERENCES_SINGLETABVERTAB")); + editorLayout->append_text (M("PREFERENCES_MULTITAB")); + editorLayout->append_text (M("PREFERENCES_MULTITABDUALMON")); + editorLayout->set_active (2); + editorLayout->signal_changed().connect (sigc::mem_fun(*this, &Preferences::layoutComboChanged)); + layoutComboChanged(); // update the tooltip + hbworkflow->pack_start (*flayoutlab, Gtk::PACK_SHRINK); + hbworkflow->pack_start (*editorLayout); + Gtk::Label* lNextStart = Gtk::manage( new Gtk::Label (Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")") ); + hbworkflow->pack_end (*lNextStart, Gtk::PACK_SHRINK); + vbworkflow->pack_start (*hbworkflow, Gtk::PACK_SHRINK); + + Gtk::HBox* curveBBoxPosHB = Gtk::manage (new Gtk::HBox (false, 4)); + Gtk::Label* curveBBoxPosL = Gtk::manage (new Gtk::Label (M("PREFERENCES_CURVEBBOXPOS")+":")); + Gtk::Label* curveBBoxPosRestartL = Gtk::manage (new Gtk::Label (Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")")); + curveBBoxPosC = Gtk::manage (new Gtk::ComboBoxText ()); + curveBBoxPosC->append_text (M("PREFERENCES_CURVEBBOXPOS_ABOVE")); + curveBBoxPosC->append_text (M("PREFERENCES_CURVEBBOXPOS_RIGHT")); + curveBBoxPosC->append_text (M("PREFERENCES_CURVEBBOXPOS_BELOW")); + curveBBoxPosC->append_text (M("PREFERENCES_CURVEBBOXPOS_LEFT")); + curveBBoxPosC->set_active (1); + curveBBoxPosHB->pack_start (*curveBBoxPosL, Gtk::PACK_SHRINK); + curveBBoxPosHB->pack_start (*curveBBoxPosC); + curveBBoxPosHB->pack_start (*curveBBoxPosRestartL, Gtk::PACK_SHRINK); + vbworkflow->pack_start (*curveBBoxPosHB, Gtk::PACK_SHRINK); + + Gtk::HBox* hbworkflow2 = Gtk::manage( new Gtk::HBox () ); + ckbHistogramPositionLeft = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_HISTOGRAMPOSITIONLEFT")) ); + hbworkflow2->pack_start (*ckbHistogramPositionLeft); + ckbHistogramWorking = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_HISTOGRAMWORKING")) ); + ckbHistogramWorking->set_tooltip_markup (M("PREFERENCES_HISTOGRAM_TOOLTIP")); + hbworkflow2->pack_start (*ckbHistogramWorking); + vbworkflow->pack_start (*hbworkflow2, Gtk::PACK_SHRINK); + + Gtk::HBox* hbworkflow3 = Gtk::manage( new Gtk::HBox () ); + ckbFileBrowserToolbarSingleRow = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_FILEBROWSERTOOLBARSINGLEROW")) ); + ckbShowFilmStripToolBar = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SHOWFILMSTRIPTOOLBAR")) ); + hbworkflow3->pack_start (*ckbFileBrowserToolbarSingleRow); + hbworkflow3->pack_start (*ckbShowFilmStripToolBar); + vbworkflow->pack_start (*hbworkflow3, Gtk::PACK_SHRINK); + + Gtk::HBox* hbworkflow4 = Gtk::manage( new Gtk::HBox (false, 4) ); + Gtk::Label* hb4label = Gtk::manage( new Gtk::Label (M("PREFERENCES_TP_LABEL")) ); + hbworkflow4->pack_start (*hb4label, Gtk::PACK_SHRINK); + ckbHideTPVScrollbar = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_TP_VSCROLLBAR")) ); + hbworkflow4->pack_start (*ckbHideTPVScrollbar, Gtk::PACK_SHRINK); + ckbUseIconNoText = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_TP_USEICONORTEXT")) ); + hbworkflow4->pack_start (*ckbUseIconNoText, Gtk::PACK_SHRINK); + vbworkflow->pack_start (*hbworkflow4, Gtk::PACK_SHRINK); + + fworklflow->add (*vbworkflow); + mvbsd->pack_start (*fworklflow, Gtk::PACK_SHRINK); + + Gtk::Frame* flang = Gtk::manage( new Gtk::Frame (M("PREFERENCES_DEFAULTLANG")) ); + Gtk::HBox* hblang = Gtk::manage( new Gtk::HBox () ); + hblang->set_border_width (4); + + ckbLangAutoDetect = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_LANGAUTODETECT")) ); + + Gtk::Label* langlab = Gtk::manage( new Gtk::Label (M("PREFERENCES_SELECTLANG")+":") ); + languages = Gtk::manage( new Gtk::ComboBoxText () ); + + std::vector langs; + parseDir (argv0 + "/languages", langs, ""); + for (size_t i=0; iappend_text (langs[i]); + } + } + + Gtk::Label* langw = Gtk::manage( new Gtk::Label (Glib::ustring(" (") + M("PREFERENCES_APPLNEXTSTARTUP") + ")") ); + hblang->pack_start (*ckbLangAutoDetect, Gtk::PACK_SHRINK, 4); + hblang->pack_start (*langlab, Gtk::PACK_SHRINK, 8); + hblang->pack_start (*languages); + hblang->pack_end (*langw, Gtk::PACK_SHRINK, 4); + flang->add (*hblang); + mvbsd->pack_start (*flang, Gtk::PACK_SHRINK, 4); + + langAutoDetectConn = ckbLangAutoDetect->signal_toggled().connect (sigc::mem_fun(*this, &Preferences::langAutoDetectToggled)); + + Gtk::Frame* ftheme = Gtk::manage( new Gtk::Frame (M("PREFERENCES_DEFAULTTHEME")) ); + Gtk::VBox* vbftheme = Gtk::manage( new Gtk::VBox () ); + vbftheme->set_border_width(4); + vbftheme->set_spacing(4); + Gtk::HBox* hbUseSystemTheme = Gtk::manage( new Gtk::HBox () ); + hbUseSystemTheme->set_spacing(4); + chUseSystemTheme = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_USESYSTEMTHEME")) ); + Gtk::Label* useNextStart = Gtk::manage( new Gtk::Label (Glib::ustring("(") + M("PREFERENCES_APPLNEXTSTARTUP") + ")") ); + + Gtk::Label* cutOverlayLabel = Gtk::manage( new Gtk::Label (M("PREFERENCES_CUTOVERLAYBRUSH") + ":") ); + butCropCol= Gtk::manage( new Gtk::ColorButton() ); + butCropCol->set_use_alpha(true); + + Gtk::Label* navGuideLabel = Gtk::manage( new Gtk::Label (M("PREFERENCES_NAVGUIDEBRUSH") + ":") ); + butNavGuideCol= Gtk::manage( new Gtk::ColorButton() ); + butNavGuideCol->set_use_alpha(true); + + slimUI = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SLIMUI")) ); + hbUseSystemTheme->pack_start(*chUseSystemTheme, Gtk::PACK_SHRINK); + hbUseSystemTheme->pack_start (*useNextStart, Gtk::PACK_SHRINK, 0); + hbUseSystemTheme->pack_end(*slimUI, Gtk::PACK_SHRINK, 0); + vbftheme->pack_start(*hbUseSystemTheme, Gtk::PACK_SHRINK, 0); + + + hbtheme = Gtk::manage( new Gtk::HBox () ); + hbtheme->set_spacing (4); + Gtk::Label* themelab = Gtk::manage( new Gtk::Label (M("PREFERENCES_SELECTTHEME")+":") ); + theme = Gtk::manage( new Gtk::ComboBoxText () ); + + theme->set_active (0); + std::vector themes; + parseDir (argv0 + "/themes", themes, ".gtkrc"); + for (size_t i=0; iappend_text (themes[i]); + + Gtk::Label* fontlab = Gtk::manage( new Gtk::Label (M("PREFERENCES_SELECTFONT")+":") ); + fontbutton = Gtk::manage( new Gtk::FontButton ()); + fontbutton->set_use_size(true); + fontbutton->set_font_name(options.font); + + hbtheme->pack_start (*themelab, Gtk::PACK_SHRINK, 0); + hbtheme->pack_start (*theme); + hbtheme->pack_start (*fontlab, Gtk::PACK_SHRINK, 0); + hbtheme->pack_start (*fontbutton); + vbftheme->pack_start(*hbtheme, Gtk::PACK_SHRINK, 0); + + + Gtk::HBox* hbcolorchooser = Gtk::manage( new Gtk::HBox () ); + hbcolorchooser->set_spacing(4); + + hbcolorchooser->pack_start (*cutOverlayLabel, Gtk::PACK_SHRINK, 0); + hbcolorchooser->pack_start (*butCropCol, Gtk::PACK_SHRINK, 0); + hbcolorchooser->pack_end (*butNavGuideCol, Gtk::PACK_SHRINK, 0); + hbcolorchooser->pack_end (*navGuideLabel, Gtk::PACK_SHRINK, 0); + vbftheme->pack_start(*hbcolorchooser, Gtk::PACK_SHRINK, 0); + + + ftheme->add (*vbftheme); + mvbsd->pack_start (*ftheme, Gtk::PACK_SHRINK, 0); + +//----- + + Gtk::HBox* hbcd = Gtk::manage( new Gtk::HBox (true) ); + hbcd->set_spacing(4); + + Gtk::Frame* frl = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CLIPPINGIND"))); + Gtk::VBox* vbrl = Gtk::manage( new Gtk::VBox () ); + vbrl->set_border_width(4); + vbrl->set_spacing (4); + + Gtk::HBox* vbhl = Gtk::manage( new Gtk::HBox () ); + vbhl->set_spacing(4); + Gtk::Label* hll = Gtk::manage( new Gtk::Label (M("PREFERENCES_HLTHRESHOLD")+": ")); + hlThresh = Gtk::manage( new Gtk::SpinButton () ); + hlThresh->set_digits (0); + hlThresh->set_increments (1, 10); + hlThresh->set_range (0, 255); + vbhl->pack_start (*hll, Gtk::PACK_SHRINK, 0); + vbhl->pack_end (*hlThresh, Gtk::PACK_SHRINK, 0); + + vbrl->pack_start (*vbhl, Gtk::PACK_SHRINK, 0); + + Gtk::HBox* vbsh = Gtk::manage( new Gtk::HBox () ); + vbsh->set_spacing (4); + Gtk::Label* shl = Gtk::manage( new Gtk::Label (M("PREFERENCES_SHTHRESHOLD")+": ") ); + shThresh = Gtk::manage( new Gtk::SpinButton () ); + shThresh->show (); + shThresh->set_digits (0); + shThresh->set_increments (1, 10); + shThresh->set_range (0, 255); + vbsh->pack_start (*shl, Gtk::PACK_SHRINK, 0); + vbsh->pack_end (*shThresh, Gtk::PACK_SHRINK, 0); + vbrl->pack_start (*vbsh, Gtk::PACK_SHRINK, 0); + + frl->add (*vbrl); + hbcd->pack_start (*frl, true, true, 0); + + //--- + + Gtk::Frame* navigationFrame = Gtk::manage( new Gtk::Frame (M("PREFERENCES_NAVIGATIONFRAME")) ); + Gtk::VBox* navigationVBox = Gtk::manage( new Gtk::VBox () ); + navigationVBox->set_border_width(4); + + Gtk::HBox* panFactorHBox = Gtk::manage( new Gtk::HBox () ); + Gtk::Label* panFactorLabel = Gtk::manage( new Gtk::Label (M("PREFERENCES_PANFACTORLABEL") + ":", Gtk::ALIGN_LEFT)); + panFactor = Gtk::manage( new Gtk::SpinButton () ); + panFactor->set_digits (0); + panFactor->set_increments (1, 5); + panFactor->set_range (1, 10); + panFactorHBox->pack_start (*panFactorLabel); + panFactorHBox->pack_end (*panFactor, Gtk::PACK_SHRINK); + + rememberZoomPanCheckbutton = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_REMEMBERZOOMPAN")) ); + rememberZoomPanCheckbutton->set_tooltip_text(M("PREFERENCES_REMEMBERZOOMPAN_TOOLTIP")); + + navigationVBox->pack_start (*panFactorHBox, Gtk::PACK_SHRINK); + navigationVBox->pack_start (*rememberZoomPanCheckbutton, Gtk::PACK_SHRINK); + navigationFrame->add (*navigationVBox); + + hbcd->pack_start (*navigationFrame); + mvbsd->pack_start (*hbcd, Gtk::PACK_SHRINK, 0); + +//----- + + Gtk::Frame* fdg = Gtk::manage( new Gtk::Frame (M("PREFERENCES_EXTERNALEDITOR")) ); + Gtk::VBox* dgvb = Gtk::manage( new Gtk::VBox () ); + + Gtk::HBox* hb7c = Gtk::manage( new Gtk::HBox () ); + edOther = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_EDITORCMDLINE")+":")); + hb7c->pack_start (*edOther, Gtk::PACK_SHRINK,4); + editorToSendTo = Gtk::manage( new Gtk::Entry () ); + hb7c->pack_start (*editorToSendTo); + Gtk::RadioButton::Group ge = edOther->get_group(); + +#ifdef __APPLE__ + Gtk::HBox* hb7 = Gtk::manage( new Gtk::HBox () ); + edGimp = Gtk::manage( new Gtk::RadioButton ("GIMP") ); + hb7->pack_start (*edGimp, Gtk::PACK_SHRINK,4); + dgvb->pack_start (*hb7, Gtk::PACK_SHRINK, 4); + edGimp->set_group (ge); + + Gtk::HBox* hb7b = Gtk::manage( new Gtk::HBox () ); + edPS = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_PSPATH")+":")); + hb7b->pack_start (*edPS, Gtk::PACK_SHRINK,4); + psDir = Gtk::manage( new Gtk::FileChooserButton (M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) ); + hb7b->pack_start (*psDir); + dgvb->pack_start (*hb7b, Gtk::PACK_SHRINK, 4); + edPS->set_group (ge); +#elif defined WIN32 + Gtk::HBox* hb7 = Gtk::manage( new Gtk::HBox () ); + edGimp = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_GIMPPATH")+":") ); + hb7->pack_start (*edGimp, Gtk::PACK_SHRINK,4); + gimpDir = Gtk::manage( new Gtk::FileChooserButton (M("PREFERENCES_GIMPPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) ); + hb7->pack_start (*gimpDir); + dgvb->pack_start (*hb7, Gtk::PACK_SHRINK, 4); + edGimp->set_group (ge); + + Gtk::HBox* hb7b = Gtk::manage( new Gtk::HBox ()); + edPS = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_PSPATH")+":") ); + hb7b->pack_start (*edPS, Gtk::PACK_SHRINK,4); + psDir = Gtk::manage( new Gtk::FileChooserButton (M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER) ); + hb7b->pack_start (*psDir); + dgvb->pack_start (*hb7b, Gtk::PACK_SHRINK, 4); + edPS->set_group (ge); +#else + Gtk::HBox* hb7 = Gtk::manage( new Gtk::HBox () ); + edGimp = Gtk::manage( new Gtk::RadioButton ("GIMP") ); + hb7->pack_start (*edGimp, Gtk::PACK_SHRINK,4); + dgvb->pack_start (*hb7, Gtk::PACK_SHRINK, 4); + edGimp->set_group (ge); +#endif + + dgvb->pack_start (*hb7c, Gtk::PACK_SHRINK, 4); + dgvb->set_border_width (4); + fdg->add (*dgvb); + mvbsd->pack_start (*fdg, Gtk::PACK_SHRINK, 4); + + + mvbsd->set_border_width (4); + + tconn = theme->signal_changed().connect( sigc::mem_fun(*this, &Preferences::themeChanged) ); + sconn = slimUI->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::themeChanged) ); + fconn = fontbutton->signal_font_set().connect( sigc::mem_fun(*this, &Preferences::fontChanged) ); + usethcon = chUseSystemTheme->signal_clicked ().connect( sigc::mem_fun(*this, &Preferences::useThemeChanged) ); + + return mvbsd; +} + +Gtk::Widget* Preferences::getFileBrowserPanel () { + + Gtk::VBox* mvbfb = Gtk::manage( new Gtk::VBox () ); + mvbfb->set_border_width (4); + + Gtk::Frame* fsd = Gtk::manage( new Gtk::Frame (M("PREFERENCES_STARTUPIMDIR")) ); + + sdcurrent = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_DIRSOFTWARE")) ); + sdlast = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_DIRLAST")) ); + sdhome = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_DIRHOME")) ); + sdother = Gtk::manage( new Gtk::RadioButton (M("PREFERENCES_DIROTHER")+": ") ); + startupdir = Gtk::manage( new Gtk::Entry () ); + + Gtk::Button* sdselect = Gtk::manage( new Gtk::Button ("") ); + sdselect->set_image (*Gtk::manage(new RTImage ("gtk-open.png"))); + + Gtk::RadioButton::Group opts = sdcurrent->get_group(); + sdlast->set_group (opts); + sdhome->set_group (opts); + sdother->set_group (opts); + + Gtk::VBox* vbsd = Gtk::manage( new Gtk::VBox () ); + vbsd->pack_start (*sdcurrent, Gtk::PACK_SHRINK,0); + vbsd->pack_start (*sdlast, Gtk::PACK_SHRINK,0); + vbsd->pack_start (*sdhome, Gtk::PACK_SHRINK,0); + Gtk::HBox* otherbox = Gtk::manage( new Gtk::HBox () ); + otherbox->pack_start (*sdother, Gtk::PACK_SHRINK); + otherbox->pack_start (*startupdir); + otherbox->pack_end (*sdselect, Gtk::PACK_SHRINK, 4); + vbsd->pack_start (*otherbox, Gtk::PACK_SHRINK, 0); + vbsd->set_border_width (4); + + fsd->add (*vbsd); + mvbfb->pack_start (*fsd, Gtk::PACK_SHRINK, 4); + + sdselect->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::selectStartupDir) ); + +//--- + + + Gtk::Frame* fro = Gtk::manage( new Gtk::Frame (M("PREFERENCES_FBROWSEROPTS")) ); + showDateTime = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SHOWDATETIME")) ); + showBasicExif = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SHOWBASICEXIF")) ); + showExpComp = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_SHOWEXPOSURECOMPENSATION")) ); + Gtk::VBox* vbro = Gtk::manage( new Gtk::VBox () ); + Gtk::HBox* hbro1 = Gtk::manage( new Gtk::HBox () ); + Gtk::HBox* hbro0 = Gtk::manage( new Gtk::HBox () ); + overlayedFileNames = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_OVERLAY_FILENAMES")) ); + filmStripOverlayedFileNames = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_OVERLAY_FILENAMES_FILMSTRIP")) ); + sameThumbSize = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT")) ); + sameThumbSize->set_tooltip_text(M("PREFERENCES_FSTRIP_SAME_THUMB_HEIGHT_HINT")); + ckbInternalThumbIfUntouched = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_INTERNALTHUMBIFUNTOUCHED"))); + + vbro->set_border_width (4); + vbro->pack_start (*showDateTime, Gtk::PACK_SHRINK, 0); + Gtk::Label* dflab = Gtk::manage( new Gtk::Label (M("PREFERENCES_DATEFORMAT")+":", Gtk::ALIGN_LEFT)); + dateformat = Gtk::manage( new Gtk::Entry () ); + dateformat->set_tooltip_markup (M("PREFERENCES_DATEFORMATHINT")); + dflab->set_tooltip_markup (M("PREFERENCES_DATEFORMATHINT")); + hbro0->pack_start (*dflab, Gtk::PACK_SHRINK, 4); + hbro0->pack_start (*dateformat, Gtk::PACK_SHRINK, 0); + + vbro->pack_start (*hbro0, Gtk::PACK_SHRINK, 0); + hbro1->pack_start (*showBasicExif, Gtk::PACK_SHRINK, 0); + hbro1->pack_start (*showExpComp, Gtk::PACK_SHRINK, 4); + vbro->pack_start (*hbro1, Gtk::PACK_SHRINK, 0); + vbro->pack_start (*overlayedFileNames, Gtk::PACK_SHRINK, 0); + vbro->pack_start (*filmStripOverlayedFileNames, Gtk::PACK_SHRINK, 0); + vbro->pack_start (*sameThumbSize, Gtk::PACK_SHRINK, 0); + vbro->pack_start (*ckbInternalThumbIfUntouched, Gtk::PACK_SHRINK, 0); + + Gtk::HBox* hbrecent = Gtk::manage( new Gtk::HBox () ); + Gtk::Label* labrecent = Gtk::manage( new Gtk::Label (M("PREFERENCES_MAXRECENTFOLDERS")+":") ); + maxRecentFolders = Gtk::manage( new Gtk::SpinButton () ); + hbrecent->pack_start (*labrecent, Gtk::PACK_SHRINK, 4); + hbrecent->pack_start (*maxRecentFolders, Gtk::PACK_SHRINK, 4); + maxRecentFolders->set_digits (0); + maxRecentFolders->set_increments (1, 5); + maxRecentFolders->set_range (1, 25); + vbro->pack_start (*hbrecent, Gtk::PACK_SHRINK, 4); + + fro->add (*vbro); + + + Gtk::Frame* frmnu = Gtk::manage( new Gtk::Frame (M("PREFERENCES_MENUOPTIONS")) ); + ckbmenuGroupRank = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_MENUGROUPRANK")) ); + ckbmenuGroupLabel = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_MENUGROUPLABEL")) ); + ckbmenuGroupFileOperations = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_MENUGROUPFILEOPERATIONS")) ); + ckbmenuGroupProfileOperations = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_MENUGROUPPROFILEOPERATIONS")) ); + ckbmenuGroupExtProg = Gtk::manage( new Gtk::CheckButton (M("PREFERENCES_MENUGROUPEXTPROGS")) ); + Gtk::VBox* vbmnu = Gtk::manage( new Gtk::VBox () ); + + vbmnu->set_border_width (4); + vbmnu->pack_start (*ckbmenuGroupRank, Gtk::PACK_SHRINK, 0); + vbmnu->pack_start (*ckbmenuGroupLabel, Gtk::PACK_SHRINK, 0); + vbmnu->pack_start (*ckbmenuGroupFileOperations, Gtk::PACK_SHRINK, 0); + vbmnu->pack_start (*ckbmenuGroupProfileOperations, Gtk::PACK_SHRINK, 0); + vbmnu->pack_start (*ckbmenuGroupExtProg, Gtk::PACK_SHRINK, 0); + + frmnu->add (*vbmnu); + + + Gtk::Frame* fre = Gtk::manage( new Gtk::Frame (M("PREFERENCES_PARSEDEXT")) ); + Gtk::VBox* vbre = Gtk::manage( new Gtk::VBox () ); + vbre->set_border_width (4); + Gtk::HBox* hb0 = Gtk::manage( new Gtk::HBox () ); + Gtk::Label* elab = Gtk::manage( new Gtk::Label (M("PREFERENCES_PARSEDEXTADD")+":") ); + hb0->pack_start (*elab, Gtk::PACK_SHRINK, 4); + extension = Gtk::manage( new Gtk::Entry () ); + extension->set_width_chars(5); + hb0->pack_start (*extension); + addExt = Gtk::manage( new Gtk::Button () ); + delExt = Gtk::manage( new Gtk::Button () ); + addExt->set_tooltip_text (M("PREFERENCES_PARSEDEXTADDHINT")); + delExt->set_tooltip_text (M("PREFERENCES_PARSEDEXTDELHINT")); + Gtk::Image* addExtImg = Gtk::manage( new RTImage ("list-add-small.png") ); + Gtk::Image* delExtImg = Gtk::manage( new RTImage ("list-remove-red-small.png") ); + addExt->add (*addExtImg); + delExt->add (*delExtImg); + hb0->pack_end (*delExt, Gtk::PACK_SHRINK, 4); + hb0->pack_end (*addExt, Gtk::PACK_SHRINK, 4); + extensions = Gtk::manage( new Gtk::TreeView () ); + Gtk::ScrolledWindow* hscrollw = Gtk::manage( new Gtk::ScrolledWindow () ); + hscrollw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); + hscrollw->add (*extensions); + extensionModel = Gtk::ListStore::create (extensionColumns); + extensions->set_model (extensionModel); + extensions->append_column_editable("Enabled", extensionColumns.enabled); + extensions->append_column("Extension", extensionColumns.ext); + extensions->set_headers_visible (false); + vbre->pack_start (*hscrollw); + vbre->pack_start (*hb0, Gtk::PACK_SHRINK, 4); + + fre->add (*vbre); + + Gtk::Frame* frc = Gtk::manage( new Gtk::Frame (M("PREFERENCES_CACHEOPTS")) ); + Gtk::VBox* vbc = Gtk::manage( new Gtk::VBox () ); + frc->add (*vbc); + vbc->set_border_width (4); + + Gtk::HBox* hb3 = Gtk::manage( new Gtk::HBox () ); + Gtk::Label* chlab = Gtk::manage( new Gtk::Label (M("PREFERENCES_CACHETHUMBHEIGHT")+":") ); + maxThumbSize = Gtk::manage( new Gtk::SpinButton () ); + hb3->pack_start (*chlab, Gtk::PACK_SHRINK, 4); + hb3->pack_start (*maxThumbSize, Gtk::PACK_SHRINK, 4); + + maxThumbSize->set_digits (0); + maxThumbSize->set_increments (1, 10); + maxThumbSize->set_range (40, 800); + vbc->pack_start (*hb3, Gtk::PACK_SHRINK, 4); + + Gtk::HBox* hb4 = Gtk::manage( new Gtk::HBox () ); + Gtk::Label* celab = Gtk::manage( new Gtk::Label (M("PREFERENCES_CACHEMAXENTRIES")+":") ); + maxCacheEntries = Gtk::manage( new Gtk::SpinButton () ); + hb4->pack_start (*celab, Gtk::PACK_SHRINK, 4); + hb4->pack_start (*maxCacheEntries, Gtk::PACK_SHRINK, 4); + + maxCacheEntries->set_digits (0); + maxCacheEntries->set_increments (1, 10); + maxCacheEntries->set_range (10, 100000); + vbc->pack_start (*hb4, Gtk::PACK_SHRINK, 4); + + Gtk::HBox* hb5 = Gtk::manage( new Gtk::HBox () ); + clearThumbnails = Gtk::manage( new Gtk::Button (M("PREFERENCES_CACHECLEARTHUMBS")) ); + clearProfiles = Gtk::manage( new Gtk::Button (M("PREFERENCES_CACHECLEARPROFILES")) ); + clearAll = Gtk::manage( new Gtk::Button (M("PREFERENCES_CACHECLEARALL")) ); + hb5->pack_start (*clearThumbnails, Gtk::PACK_SHRINK, 4); + hb5->pack_start (*clearProfiles, Gtk::PACK_SHRINK, 4); + hb5->pack_start (*clearAll, Gtk::PACK_SHRINK, 4); + vbc->pack_start (*hb5, Gtk::PACK_SHRINK, 4); + + Gtk::HBox* hb6 = Gtk::manage( new Gtk::HBox () ); + Gtk::VBox* vb6 = Gtk::manage( new Gtk::VBox () ); + + vb6->pack_start (*fro); + vb6->pack_start (*frmnu); + vb6->pack_end (*frc); + hb6->pack_start (*vb6); + hb6->pack_start (*fre); + hb6->set_spacing(4); + + mvbfb->pack_start (*hb6, Gtk::PACK_SHRINK, 4); + +// mvbfb->pack_start (*fro, Gtk::PACK_SHRINK, 4); +// mvbfb->pack_start (*fre); +// mvbfb->pack_start (*frc, Gtk::PACK_SHRINK, 4); + + addExt->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::addExtPressed) ); + delExt->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::delExtPressed) ); + extension->signal_activate().connect( sigc::mem_fun(*this, &Preferences::addExtPressed) ); + clearThumbnails->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::clearThumbImagesPressed) ); + clearProfiles->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::clearProfilesPressed) ); + clearAll->signal_clicked().connect( sigc::mem_fun(*this, &Preferences::clearAllPressed) ); + + return mvbfb; +} + +Gtk::Widget* Preferences::getSoundPanel () { + Gtk::VBox* pSnd = new Gtk::VBox (); + + ckbSndEnable = Gtk::manage( new Gtk::CheckButton (M("GENERAL_ENABLE"))); + sndEnableConn = ckbSndEnable->signal_toggled().connect (sigc::mem_fun(*this, &Preferences::sndEnableToggled)); + + pSnd->pack_start (*ckbSndEnable, Gtk::PACK_SHRINK, 4); + + Gtk::HBox* hblSndHelp = Gtk::manage (new Gtk::HBox ()); + Gtk::Label* lSndHelp = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_HELP"))); + hblSndHelp->pack_start (*lSndHelp, Gtk::PACK_SHRINK, 4); + pSnd->pack_start (*hblSndHelp, Gtk::PACK_SHRINK, 4); + + // BatchQueueDone + Gtk::HBox* pBatchQueueDone = Gtk::manage( new Gtk::HBox() ); + + Gtk::Label* lSndBatchQueueDone = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_BATCHQUEUEDONE") + Glib::ustring(":"))); + pBatchQueueDone->pack_start (*lSndBatchQueueDone, Gtk::PACK_SHRINK, 4); + + txtSndBatchQueueDone = Gtk::manage (new Gtk::Entry()); + pBatchQueueDone->pack_end (*txtSndBatchQueueDone, Gtk::PACK_EXPAND_WIDGET, 4); + + pSnd->pack_start (*pBatchQueueDone, Gtk::PACK_SHRINK, 4); + + // LngEditProcDone + Gtk::HBox* pSndLngEditProcDone = Gtk::manage( new Gtk::HBox() ); + + Gtk::Label* lSndLngEditProcDone = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_LNGEDITPROCDONE") + Glib::ustring(":"))); + pSndLngEditProcDone->pack_start (*lSndLngEditProcDone, Gtk::PACK_SHRINK, 4); + + txtSndLngEditProcDone = Gtk::manage (new Gtk::Entry()); + pSndLngEditProcDone->pack_start (*txtSndLngEditProcDone, Gtk::PACK_EXPAND_WIDGET, 4); + + Gtk::Label* lSndLngEditProcDoneSecs = Gtk::manage (new Gtk::Label (M("PREFERENCES_SND_TRESHOLDSECS") + Glib::ustring(":"))); + pSndLngEditProcDone->pack_start (*lSndLngEditProcDoneSecs, Gtk::PACK_SHRINK, 12); + + spbSndLngEditProcDoneSecs = Gtk::manage( new Gtk::SpinButton () ); + spbSndLngEditProcDoneSecs->set_digits (1); + spbSndLngEditProcDoneSecs->set_increments (0.5, 1); + spbSndLngEditProcDoneSecs->set_range (0, 10); + pSndLngEditProcDone->pack_end (*spbSndLngEditProcDoneSecs, Gtk::PACK_SHRINK, 4); + + pSnd->pack_start (*pSndLngEditProcDone, Gtk::PACK_SHRINK, 4); + + pSnd->set_border_width (4); + + sndEnableToggled(); + + return pSnd; +} + +void Preferences::parseDir (Glib::ustring dirname, std::vector& items, Glib::ustring ext) { + + if (dirname.empty()) + return; + + // process directory + Glib::Dir* dir = NULL; + try { + dir = new Glib::Dir (dirname); + } + catch (const Glib::Error& e) { + return; + } + for (Glib::DirIterator i = dir->begin(); i!=dir->end(); ++i) { + Glib::ustring fname = Glib::build_filename(dirname, *i); + Glib::ustring sname = *i; + // ignore directories + if (!safe_file_test (fname, Glib::FILE_TEST_IS_DIR) && sname.size() >= ext.size() && sname.substr (sname.size()-ext.size(), ext.size()).casefold() == ext) + items.push_back (sname.substr(0,sname.size()-ext.size())); + } + std::sort(items.begin(), items.end()); + delete dir; +} + +void Preferences::storePreferences () { + + // With the new mechanism, we can't be sure of the availability of the DEFPROFILE_RAW & DEFPROFILE_IMG profiles, + // because useBundledProfiles may be false. We're now using DEFPROFILE_INTERNAL instead, which is always available. + moptions.defProfRaw = rprofiles->getFullPathFromActiveRow(); + if (moptions.defProfRaw.empty()) moptions.defProfRaw = DEFPROFILE_INTERNAL; + moptions.defProfImg = iprofiles->getFullPathFromActiveRow(); + if (moptions.defProfImg.empty()) moptions.defProfImg = DEFPROFILE_INTERNAL; + + moptions.dateFormat = dateformat->get_text(); + moptions.panAccelFactor = (int)panFactor->get_value(); + moptions.rememberZoomAndPan = rememberZoomPanCheckbutton->get_active(); + moptions.fbShowDateTime = showDateTime->get_active (); + moptions.fbShowBasicExif = showBasicExif->get_active (); + moptions.fbShowExpComp = showExpComp->get_active (); + moptions.menuGroupRank = ckbmenuGroupRank->get_active(); + moptions.menuGroupLabel = ckbmenuGroupLabel->get_active(); + moptions.menuGroupFileOperations = ckbmenuGroupFileOperations->get_active(); + moptions.menuGroupProfileOperations = ckbmenuGroupProfileOperations->get_active(); + moptions.menuGroupExtProg = ckbmenuGroupExtProg->get_active(); + moptions.highlightThreshold = (int)hlThresh->get_value (); + moptions.shadowThreshold = (int)shThresh->get_value (); + moptions.language = languages->get_active_text (); + moptions.languageAutoDetect = ckbLangAutoDetect->get_active (); + moptions.theme = theme->get_active_text (); + moptions.slimUI = slimUI->get_active (); + moptions.useSystemTheme = chUseSystemTheme->get_active (); + + Gdk::Color cropCol=butCropCol->get_color(); + moptions.cutOverlayBrush[0]=cropCol.get_red_p(); + moptions.cutOverlayBrush[1]=cropCol.get_green_p(); + moptions.cutOverlayBrush[2]=cropCol.get_blue_p(); + moptions.cutOverlayBrush[3]=butCropCol->get_alpha()/65535.0; + + Gdk::Color NavGuideCol=butNavGuideCol->get_color(); + moptions.navGuideBrush[0]=NavGuideCol.get_red_p(); + moptions.navGuideBrush[1]=NavGuideCol.get_green_p(); + moptions.navGuideBrush[2]=NavGuideCol.get_blue_p(); + moptions.navGuideBrush[3]=butNavGuideCol->get_alpha()/65535.0; + + moptions.font = fontbutton->get_font_name(); +#ifdef WIN32 + moptions.gimpDir = gimpDir->get_filename (); + moptions.psDir = psDir->get_filename (); +#elif defined __APPLE__ + moptions.psDir = psDir->get_filename (); +#endif + moptions.customEditorProg = editorToSendTo->get_text (); + if (edGimp->get_active ()) + moptions.editorToSendTo = 1; +#ifdef WIN32 + else if (edPS->get_active ()) + moptions.editorToSendTo = 2; +#elif defined __APPLE__ + else if (edPS->get_active ()) + moptions.editorToSendTo = 2; +#endif + else if (edOther->get_active ()) + moptions.editorToSendTo = 3; + + moptions.CPBPath = txtCustProfBuilderPath->get_text(); + moptions.CPBKeys = CPBKeyType(custProfBuilderLabelType->get_active_row_number()); + + moptions.rtSettings.monitorProfile = monProfile->get_filename (); +#if defined(WIN32) + moptions.rtSettings.autoMonitorProfile = cbAutoMonProfile->get_active (); +#endif + moptions.rtSettings.iccDirectory = iccDir->get_filename (); + moptions.rtSettings.colorimetricIntent = intent->get_active_row_number (); + moptions.rtSettings.viewingdevice = view->get_active_row_number (); + moptions.rtSettings.viewingdevicegrey = grey->get_active_row_number (); + moptions.rtSettings.viewinggreySc = greySc->get_active_row_number (); + // moptions.rtSettings.autocielab = cbAutocielab->get_active (); + moptions.rtSettings.ciecamfloat = cbciecamfloat->get_active (); + moptions.rtSettings.HistogramWorking = ckbHistogramWorking->get_active (); + moptions.rtSettings.leveldnv = dnv->get_active_row_number (); + moptions.rtSettings.leveldnti = dnti->get_active_row_number (); + moptions.rtSettings.leveldnliss = dnliss->get_active_row_number (); + moptions.rtSettings.leveldnaut = dnaut->get_active_row_number (); + moptions.rtSettings.nrwavlevel = dnwavlev->get_active_row_number (); + moptions.rtSettings.leveldnautsimpl = dnautsimpl->get_active_row_number (); + moptions.rtSettings.daubech = cbdaubech->get_active (); + + moptions.prevdemo = (prevdemo_t)cprevdemo->get_active_row_number (); + moptions.serializeTiffRead = ctiffserialize->get_active(); + if (sdcurrent->get_active ()) + moptions.startupDir = STARTUPDIR_CURRENT; + else if (sdhome->get_active ()) + moptions.startupDir = STARTUPDIR_HOME; + else if (sdlast->get_active ()) + moptions.startupDir = STARTUPDIR_LAST; + else if (sdother->get_active ()) { + moptions.startupDir = STARTUPDIR_CUSTOM; + moptions.startupPath = startupdir->get_text(); + } + + moptions.parseExtensions.clear (); + moptions.parseExtensionsEnabled.clear (); + Gtk::TreeNodeChildren c = extensionModel->children (); + for (size_t i=0; iget_value(); + moptions.maxThumbnailHeight = (int)maxThumbSize->get_value (); + moptions.maxCacheEntries = (int)maxCacheEntries->get_value (); + moptions.overlayedFileNames = overlayedFileNames->get_active (); + moptions.filmStripOverlayedFileNames = filmStripOverlayedFileNames->get_active(); + moptions.sameThumbSize = sameThumbSize->get_active(); + moptions.internalThumbIfUntouched = ckbInternalThumbIfUntouched->get_active (); + + moptions.saveParamsFile = saveParamsFile->get_active (); + moptions.saveParamsCache = saveParamsCache->get_active (); + moptions.paramsLoadLocation = (PPLoadLocation)loadParamsPreference->get_active_row_number (); + moptions.useBundledProfiles = useBundledProfiles->get_active (); + + moptions.tunnelMetaData = ckbTunnelMetaData->get_active (); + + moptions.rtSettings.darkFramesPath = darkFrameDir->get_filename(); + moptions.rtSettings.flatFieldsPath = flatFieldDir->get_filename(); + + moptions.clutsDir = clutsDir->get_filename(); + + moptions.baBehav.resize (ADDSET_PARAM_NUM); + for (Gtk::TreeIter sections=behModel->children().begin(); sections!=behModel->children().end(); sections++) + for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) + moptions.baBehav[adjs->get_value (behavColumns.addsetid)] = adjs->get_value (behavColumns.badd); + + int editorMode=editorLayout->get_active_row_number(); + moptions.tabbedUI = (editorMode>1); + moptions.multiDisplayMode = editorMode==3 ? 1:0; + moptions.mainNBVertical = editorMode==1; + + moptions.curvebboxpos = curveBBoxPosC->get_active_row_number(); + moptions.histogramPosition = ckbHistogramPositionLeft->get_active() ? 1 : 2; + moptions.FileBrowserToolbarSingleRow = ckbFileBrowserToolbarSingleRow->get_active(); + moptions.showFilmStripToolBar = ckbShowFilmStripToolBar->get_active(); + moptions.hideTPVScrollbar = ckbHideTPVScrollbar->get_active(); + moptions.overwriteOutputFile = chOverwriteOutputFile->get_active (); + moptions.UseIconNoText = ckbUseIconNoText->get_active(); + + moptions.rgbDenoiseThreadLimit = rgbDenoiseTreadLimitSB->get_value_as_int(); + moptions.clutCacheSize = clutCacheSizeSB->get_value_as_int(); + moptions.maxInspectorBuffers = maxInspectorBuffersSB->get_value_as_int(); + + // Sounds only on Windows and Linux +#if defined(WIN32) || defined(__linux__) + moptions.sndEnable = ckbSndEnable->get_active (); + moptions.sndBatchQueueDone = txtSndBatchQueueDone->get_text (); + moptions.sndLngEditProcDone = txtSndLngEditProcDone->get_text (); + moptions.sndLngEditProcDoneSecs = spbSndLngEditProcDoneSecs->get_value (); +#endif +} + +void Preferences::fillPreferences () { + + tconn.block (true); + sconn.block (true); + dfconn.block (true); + ffconn.block (true); + rpconn.block(true); + ipconn.block(true); + bpconn.block(true); + + rprofiles->setActiveRowFromFullPath (moptions.defProfRaw); + forRAWComboChanged(); // update the tooltip + iprofiles->setActiveRowFromFullPath (moptions.defProfImg); + forImageComboChanged(); // update the tooltip + dateformat->set_text (moptions.dateFormat); + panFactor->set_value (moptions.panAccelFactor); + rememberZoomPanCheckbutton->set_active (moptions.rememberZoomAndPan); + ctiffserialize->set_active(moptions.serializeTiffRead); +#if !defined(__APPLE__) // monitor profile not supported on apple + if (safe_file_test (moptions.rtSettings.monitorProfile, Glib::FILE_TEST_EXISTS)) + monProfile->set_filename (moptions.rtSettings.monitorProfile); + if (moptions.rtSettings.monitorProfile.empty()) + monProfile->set_current_folder (moptions.rtSettings.iccDirectory); +#if defined(WIN32) + cbAutoMonProfile->set_active(moptions.rtSettings.autoMonitorProfile); +#endif +#endif + + if (Glib::file_test (moptions.rtSettings.iccDirectory, Glib::FILE_TEST_IS_DIR)) + iccDir->set_current_folder (moptions.rtSettings.iccDirectory); + intent->set_active (moptions.rtSettings.colorimetricIntent); + view->set_active (moptions.rtSettings.viewingdevice); + grey->set_active (moptions.rtSettings.viewingdevicegrey); + greySc->set_active (moptions.rtSettings.viewinggreySc); + dnv->set_active (moptions.rtSettings.leveldnv); + dnti->set_active (moptions.rtSettings.leveldnti); + dnliss->set_active (moptions.rtSettings.leveldnliss); + dnaut->set_active (moptions.rtSettings.leveldnaut); + dnautsimpl->set_active (moptions.rtSettings.leveldnautsimpl); + dnwavlev->set_active (moptions.rtSettings.nrwavlevel); + cprevdemo->set_active (moptions.prevdemo); + cbdaubech->set_active (moptions.rtSettings.daubech); + +// cbAutocielab->set_active (moptions.rtSettings.autocielab); + cbciecamfloat->set_active (moptions.rtSettings.ciecamfloat); + ckbHistogramWorking->set_active (moptions.rtSettings.HistogramWorking); + languages->set_active_text (moptions.language); + ckbLangAutoDetect->set_active (moptions.languageAutoDetect); + theme->set_active_text (moptions.theme); + slimUI->set_active(moptions.slimUI); + chUseSystemTheme->set_active(moptions.useSystemTheme); + + Gdk::Color cropCol; + cropCol.set_rgb_p(moptions.cutOverlayBrush[0],moptions.cutOverlayBrush[1],moptions.cutOverlayBrush[2]); + butCropCol->set_color(cropCol); + butCropCol->set_alpha ( (unsigned short)(moptions.cutOverlayBrush[3]*65535.0)); + + Gdk::Color NavGuideCol; + NavGuideCol.set_rgb_p(moptions.navGuideBrush[0],moptions.navGuideBrush[1],moptions.navGuideBrush[2]); + butNavGuideCol->set_color(NavGuideCol); + butNavGuideCol->set_alpha ( (unsigned short)(moptions.navGuideBrush[3]*65535.0)); + + fontbutton->set_font_name(moptions.font); + showDateTime->set_active (moptions.fbShowDateTime); + showBasicExif->set_active (moptions.fbShowBasicExif); + showExpComp->set_active (moptions.fbShowExpComp); + ckbmenuGroupRank->set_active(moptions.menuGroupRank); + ckbmenuGroupLabel->set_active(moptions.menuGroupLabel); + ckbmenuGroupFileOperations->set_active(moptions.menuGroupFileOperations); + ckbmenuGroupProfileOperations->set_active(moptions.menuGroupProfileOperations); + ckbmenuGroupExtProg->set_active(moptions.menuGroupExtProg); + + hlThresh->set_value (moptions.highlightThreshold); + shThresh->set_value (moptions.shadowThreshold); + + edGimp->set_active (moptions.editorToSendTo==1); + edOther->set_active (moptions.editorToSendTo==3); +#ifdef WIN32 + edPS->set_active (moptions.editorToSendTo==2); + if (safe_file_test (moptions.gimpDir, Glib::FILE_TEST_IS_DIR)) + gimpDir->set_current_folder (moptions.gimpDir); + if (safe_file_test (moptions.psDir, Glib::FILE_TEST_IS_DIR)) + psDir->set_current_folder (moptions.psDir); +#elif defined __APPLE__ + edPS->set_active (moptions.editorToSendTo==2); + if (safe_file_test (moptions.psDir, Glib::FILE_TEST_IS_DIR)) + psDir->set_current_folder (moptions.psDir); +#endif + editorToSendTo->set_text (moptions.customEditorProg); + + txtCustProfBuilderPath->set_text(moptions.CPBPath); + custProfBuilderLabelType->set_active(moptions.CPBKeys); + + + if (moptions.startupDir==STARTUPDIR_CURRENT) + sdcurrent->set_active (); + else if (moptions.startupDir==STARTUPDIR_LAST) + sdlast->set_active (); + else if (moptions.startupDir==STARTUPDIR_HOME) + sdhome->set_active (); + else if (moptions.startupDir==STARTUPDIR_CUSTOM) { + sdother->set_active (); + startupdir->set_text (moptions.startupPath); + } + + extensionModel->clear (); + for (size_t i=0; iappend()); + row[extensionColumns.enabled] = moptions.parseExtensionsEnabled[i]; + row[extensionColumns.ext] = moptions.parseExtensions[i]; + } + + maxThumbSize->set_value (moptions.maxThumbnailHeight); + maxRecentFolders->set_value(moptions.maxRecentFolders); + maxCacheEntries->set_value (moptions.maxCacheEntries); + overlayedFileNames->set_active (moptions.overlayedFileNames); + filmStripOverlayedFileNames->set_active(moptions.filmStripOverlayedFileNames); + sameThumbSize->set_active(moptions.sameThumbSize); + ckbInternalThumbIfUntouched->set_active(moptions.internalThumbIfUntouched); + + saveParamsFile->set_active (moptions.saveParamsFile); + saveParamsCache->set_active (moptions.saveParamsCache); + loadParamsPreference->set_active (moptions.paramsLoadLocation); + useBundledProfiles->set_active (moptions.useBundledProfiles); + + ckbTunnelMetaData->set_active (moptions.tunnelMetaData); + + if (!moptions.tabbedUI) + editorLayout->set_active(moptions.mainNBVertical ? 1 : 0); + else + editorLayout->set_active(moptions.multiDisplayMode ? 3 : 2); + + curveBBoxPosC->set_active(moptions.curvebboxpos); + ckbHistogramPositionLeft->set_active(moptions.histogramPosition==1); + // ckbHistogramWorking->set_active(moptions.histogramWorking==1); + ckbFileBrowserToolbarSingleRow->set_active(moptions.FileBrowserToolbarSingleRow); + ckbShowFilmStripToolBar->set_active(moptions.showFilmStripToolBar); + ckbHideTPVScrollbar->set_active(moptions.hideTPVScrollbar); + ckbUseIconNoText->set_active(moptions.UseIconNoText); + + rgbDenoiseTreadLimitSB->set_value(moptions.rgbDenoiseThreadLimit); + clutCacheSizeSB->set_value(moptions.clutCacheSize); + maxInspectorBuffersSB->set_value(moptions.maxInspectorBuffers); + + darkFrameDir->set_current_folder( moptions.rtSettings.darkFramesPath ); + darkFrameChanged (); + + flatFieldDir->set_current_folder( moptions.rtSettings.flatFieldsPath ); + flatFieldChanged (); + + clutsDir->set_current_folder( moptions.clutsDir ); + + addc.block (true); + setc.block (true); + if (moptions.baBehav.size() == ADDSET_PARAM_NUM) { + for (size_t i=0; ichildren().begin(); sections!=behModel->children().end(); sections++) + for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) + if (adjs->get_value (behavColumns.addsetid) == (int)i) { + adjs->set_value (behavColumns.badd, moptions.baBehav[i]==1); + adjs->set_value (behavColumns.bset, moptions.baBehav[i]!=1); + break; + } + } + addc.block (false); + setc.block (false); + tconn.block (false); + sconn.block (false); + dfconn.block (false); + ffconn.block (false); + rpconn.block(true); + ipconn.block(true); + bpconn.block(false); + + chOverwriteOutputFile->set_active (moptions.overwriteOutputFile); + + // Sounds only on Windows and Linux +#if defined(WIN32) || defined(__linux__) + ckbSndEnable->set_active (moptions.sndEnable); + txtSndBatchQueueDone->set_text (moptions.sndBatchQueueDone); + txtSndLngEditProcDone->set_text (moptions.sndLngEditProcDone); + spbSndLngEditProcDoneSecs->set_value (moptions.sndLngEditProcDoneSecs); +#endif +} + +/* +void Preferences::loadPressed () { + + moptions.copyFrom (&options); + fillPreferences (); +} + +void Preferences::savePressed () { + + storePreferences (); + options.copyFrom (&moptions); + Options::save (); +} +*/ + +#if defined(WIN32) +void Preferences::autoMonProfileToggled () { + monProfile->set_sensitive(!cbAutoMonProfile->get_active()); +} +#endif +/* +void Preferences::autocielabToggled () { +// cbAutocielab->set_sensitive(cbAutocielab->get_active()); +} +*/ +void Preferences::sndEnableToggled () { + txtSndBatchQueueDone->set_sensitive(ckbSndEnable->get_active()); + txtSndLngEditProcDone->set_sensitive(ckbSndEnable->get_active()); + spbSndLngEditProcDoneSecs->set_sensitive(ckbSndEnable->get_active()); +} + +void Preferences::langAutoDetectToggled () { + languages->set_sensitive(!ckbLangAutoDetect->get_active()); +} + +void Preferences::okPressed () { + + storePreferences (); + workflowUpdate(); + options.copyFrom (&moptions); + options.filterOutParsedExtensions(); + Options::save (); + hide (); +} + +void Preferences::cancelPressed () { + + bool currentSlimState = options.slimUI; + options.slimUI = oldSlimUI; + + // set the initial theme back + if (theme->get_active_text()!=options.theme || options.slimUI!=currentSlimState) { + RTImage::setPaths(options); + RTImage::updateImages(); + switchThemeTo(options.theme, options.slimUI); + } + + // set the initial font back + if (fontbutton->get_font_name() != options.font) + switchFontTo(options.font); + + // update the profileStore + if (useBundledProfiles->get_active () != options.useBundledProfiles) { + // we have to rescan with the old value; + bpconn.block(true); + useBundledProfiles->set_active (false); + bundledProfilesChanged(); + bpconn.block(false); + } + + hide (); +} + +void Preferences::selectStartupDir () { + + Gtk::FileChooserDialog dialog(M("PREFERENCES_DIRSELECTDLG"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); +// dialog.set_transient_for(*this); + + //Add response buttons the the dialog: + dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::StockID("gtk-open"), Gtk::RESPONSE_OK); + + int result = dialog.run(); + + if (result==Gtk::RESPONSE_OK) + startupdir->set_text (dialog.get_filename()); +} + +void Preferences::aboutPressed () { + + splash = new Splash (*this); + splash->set_transient_for (*this); + splash->signal_delete_event().connect( sigc::mem_fun(*this, &Preferences::splashClosed) ); + splash->show (); +} + +void Preferences::themeChanged () { + + moptions.theme = theme->get_active_text (); + moptions.useSystemTheme = chUseSystemTheme->get_active (); + RTImage::setPaths(moptions); + RTImage::updateImages(); + switchThemeTo(theme->get_active_text (), slimUI->get_active()); +} + +void Preferences::forRAWComboChanged () { + if (!rprofiles) + return; + const ProfileStoreEntry *selectedEntry = rprofiles->getSelectedEntry(); + if (!selectedEntry) + return; + + if (selectedEntry->type == PSET_FOLDER) { + rpconn.block(true); + rprofiles->set_active(currRawRow); + rpconn.block(false); + } + else + currRawRow = rprofiles->get_active(); + + rprofiles->set_tooltip_text(selectedEntry->label); +} + +void Preferences::forImageComboChanged () { + if (!iprofiles) + return; + const ProfileStoreEntry *selectedEntry = iprofiles->getSelectedEntry(); + if (!selectedEntry) + return; + + if (selectedEntry->type == PSET_FOLDER) { + ipconn.block(true); + iprofiles->set_active(currImgRow); + ipconn.block(false); + } + else + currImgRow = rprofiles->get_active(); + iprofiles->set_tooltip_text(iprofiles->getSelectedEntry()->label); +} + +void Preferences::layoutComboChanged () { + editorLayout->set_tooltip_text(editorLayout->get_active_text()); +} + +void Preferences::bundledProfilesChanged () { + rpconn.block (true); + ipconn.block (true); + + // parseProfiles does use options.useBundledProfiles, so we temporarily change its value + bool currValue = options.useBundledProfiles; + options.useBundledProfiles = useBundledProfiles->get_active (); + + // rescan the file's tree + profileStore.parseProfiles(); // This will call Preferences::updateProfileList in return + + // restoring back the old value + options.useBundledProfiles = currValue; + + ipconn.block (false); + rpconn.block (false); +} + +void Preferences::storeCurrentValue() { + // TODO: Find a way to get and restore the current selection; the following line can't work anymore + storedValueRaw = rprofiles->getFullPathFromActiveRow(); + storedValueImg = iprofiles->getFullPathFromActiveRow(); +} + +void Preferences::updateProfileList() { + rprofiles->updateProfileList(); + iprofiles->updateProfileList(); +} + +void Preferences::restoreValue() { + if (!rprofiles->setActiveRowFromFullPath(storedValueRaw)) { + moptions.defProfRaw = DEFPROFILE_INTERNAL; + rpconn.block(true); + rprofiles->setInternalEntry(); + rpconn.block(false); + } + currRawRow = rprofiles->get_active(); + + if (!iprofiles->setActiveRowFromFullPath(storedValueImg)) { + moptions.defProfImg = DEFPROFILE_INTERNAL; + ipconn.block(true); + iprofiles->setInternalEntry(); + ipconn.block(false); + } + currImgRow = iprofiles->get_active(); + + storedValueRaw = ""; + storedValueImg = ""; +} + +void Preferences::fontChanged () { + + switchFontTo(fontbutton->get_font_name()); +} + +void Preferences::switchThemeTo(Glib::ustring newTheme, bool slimInterface) { + + std::vector files; + files.push_back (argv0+"/themes/"+newTheme+".gtkrc"); + + options.slimUI = slimInterface; + + if (slimInterface) + files.push_back (argv0+"/themes/slim"); + Gtk::RC::set_default_files (files); + +#ifndef WIN32 + // For an unknown reason, gtkmm 2.22 don't know the gtk-button-images property, while it exists in the documentation... + // Anyway, the problem was Linux only + static Glib::RefPtr settings = Gtk::Settings::get_default(); + if (settings) + settings->property_gtk_button_images().set_value(true); + else + printf("Error: no default settings to update!\n"); +#endif + + Gtk::RC::reparse_all (Gtk::Settings::get_default()); + GdkEventClient event = { GDK_CLIENT_EVENT, NULL, TRUE, gdk_atom_intern("_GTK_READ_RCFILES", FALSE), 8 }; + gdk_event_send_clientmessage_toall ((GdkEvent*)&event); +} + +void Preferences::workflowUpdate (){ + + if(moptions.tabbedUI != options.tabbedUI) { + parent->MoveFileBrowserToMain(); + parent->CloseOpenEditors(); + parent->SetMainCurrent(); + if(moptions.tabbedUI){ + parent->epanel->hide_all(); + parent->set_title_decorated(""); + } + else{ + parent->epanel->show_all(); + parent->set_title_decorated(parent->epanel->getFileName()); + } + } + if(moptions.hideTPVScrollbar != options.hideTPVScrollbar) { + // Update the tool panels + parent->updateTPVScrollbar (moptions.hideTPVScrollbar); + } + if(moptions.UseIconNoText != options.UseIconNoText) { + // Update the tool's tab titles + parent->updateTabsUsesIcons(moptions.UseIconNoText); + } + if(moptions.FileBrowserToolbarSingleRow != options.FileBrowserToolbarSingleRow) { + // Update the position of the Query toolbar + parent->updateFBQueryTB(moptions.FileBrowserToolbarSingleRow); + } + if(moptions.showFilmStripToolBar != options.showFilmStripToolBar) { + // Update the visibility of FB toolbar + parent->updateFBToolBarVisibility(moptions.showFilmStripToolBar); + } + if(moptions.histogramPosition != options.histogramPosition) { + // Update the position of the Histogram + parent->updateHistogramPosition(options.histogramPosition, moptions.histogramPosition); + } + +} + +void Preferences::switchFontTo(Glib::ustring newFont) { + + Gtk::RC::parse_string (Glib::ustring::compose( + "style \"clearlooks-default\" { font_name = \"%1\" }", newFont)); + Gtk::RC::reparse_all (Gtk::Settings::get_default()); + GdkEventClient event = { GDK_CLIENT_EVENT, NULL, TRUE, gdk_atom_intern("_GTK_READ_RCFILES", FALSE), 8 }; + gdk_event_send_clientmessage_toall ((GdkEvent*)&event); +} + +void Preferences::useThemeChanged(){ + + if(!chUseSystemTheme->get_active()){ + hbtheme->set_sensitive(true); + fontbutton->set_sensitive(true); + } + else{ + hbtheme->set_sensitive(false); + fontbutton->set_sensitive(false); + } +} + +void Preferences::addExtPressed () { + + Gtk::TreeNodeChildren c = extensionModel->children (); + for (size_t i=0; iget_text ()) + return; + + Gtk::TreeRow row = *(extensionModel->append()); + + row[extensionColumns.enabled] = true; + row[extensionColumns.ext] = extension->get_text (); +} + +void Preferences::delExtPressed () { + + extensionModel->erase (extensions->get_selection()->get_selected ()); +} + +void Preferences::clearProfilesPressed () { + + cacheMgr->clearProfiles (); +} + +void Preferences::clearThumbImagesPressed () { + + cacheMgr->clearThumbImages (); +} + +void Preferences::clearAllPressed () { + + cacheMgr->clearAll (); +} + +void Preferences::darkFrameChanged () +{ + //Glib::ustring s(darkFrameDir->get_filename()); + Glib::ustring s(darkFrameDir->get_current_folder()); + //if( s.compare( rtengine::dfm.getPathname()) !=0 ){ + rtengine::dfm.init( s ); + updateDFinfos(); + //} +} + +void Preferences::flatFieldChanged () +{ + //Glib::ustring s(flatFieldDir->get_filename()); + Glib::ustring s(flatFieldDir->get_current_folder()); + //if( s.compare( rtengine::ffm.getPathname()) !=0 ){ + rtengine::ffm.init( s ); + updateFFinfos(); + //} +} + +void Preferences::updateDFinfos() +{ + int t1,t2; + rtengine::dfm.getStat(t1,t2); + Glib::ustring s = Glib::ustring::compose("%1: %2 %3, %4 %5", M("PREFERENCES_DARKFRAMEFOUND"), t1, M("PREFERENCES_DARKFRAMESHOTS"), t2, M("PREFERENCES_DARKFRAMETEMPLATES")); + dfLabel->set_text(s); +} + +void Preferences::updateFFinfos() +{ + int t1,t2; + rtengine::ffm.getStat(t1,t2); + Glib::ustring s = Glib::ustring::compose("%1: %2 %3, %4 %5", M("PREFERENCES_FLATFIELDFOUND"), t1, M("PREFERENCES_FLATFIELDSHOTS"), t2, M("PREFERENCES_FLATFIELDTEMPLATES")); + ffLabel->set_text(s); +} + +bool Preferences::splashClosed(GdkEventAny* event) { + delete splash; + splash = NULL; + return true; +} + +void Preferences::behAddAllPressed () { + + if (moptions.baBehav.size() == ADDSET_PARAM_NUM) { + for (size_t i=0; ichildren().begin(); sections!=behModel->children().end(); sections++) + for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) + if (adjs->get_value (behavColumns.addsetid) == (int)i) { + adjs->set_value (behavColumns.badd, true); + adjs->set_value (behavColumns.bset, false); + break; + } + } +} + +void Preferences::behSetAllPressed () { + + if (moptions.baBehav.size() == ADDSET_PARAM_NUM) { + for (size_t i=0; ichildren().begin(); sections!=behModel->children().end(); sections++) + for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) + if (adjs->get_value (behavColumns.addsetid) == (int)i) { + adjs->set_value (behavColumns.badd, false); + adjs->set_value (behavColumns.bset, true); + break; + } + } +} diff --git a/rtgui/preferences.h b/rtgui/preferences.h index a81dec5a4..f1cccc16e 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -1,250 +1,250 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef __PREFERENCES_H__ -#define __PREFERENCES_H__ - -#include -#include "adjuster.h" -#include "options.h" -#include -#include "rtwindow.h" - -class Preferences : public Gtk::Dialog, public ProfileStoreListener { - - class ExtensionColumns : public Gtk::TreeModel::ColumnRecord { - public: - Gtk::TreeModelColumn enabled; - Gtk::TreeModelColumn ext; - ExtensionColumns() { add(enabled); add(ext); } - }; - ExtensionColumns extensionColumns; - Glib::RefPtr extensionModel; - - - class BehavColumns : public Gtk::TreeModel::ColumnRecord { - public: - Gtk::TreeModelColumn label; - Gtk::TreeModelColumn badd; - Gtk::TreeModelColumn bset; - Gtk::TreeModelColumn visible; - Gtk::TreeModelColumn addsetid; - BehavColumns() { add(label); add(badd); add(bset); add(visible); add(addsetid); } - }; - Glib::RefPtr behModel; - BehavColumns behavColumns; - - - protected: - Splash* splash; - ProfileStoreComboBox* rprofiles; - Gtk::TreeIter currRawRow; // :) - ProfileStoreComboBox* iprofiles; - Gtk::TreeIter currImgRow; - Gtk::ComboBoxText* languages; - Gtk::CheckButton* ckbLangAutoDetect; - Gtk::Entry* dateformat; - Gtk::Entry* startupdir; - Gtk::RadioButton* sdcurrent; - Gtk::RadioButton* sdlast; - Gtk::RadioButton* sdhome; - Gtk::RadioButton* sdother; - Gtk::FileChooserButton* gimpDir; - Gtk::FileChooserButton* psDir; - Gtk::Entry* editorToSendTo; - Gtk::RadioButton* edGimp; - Gtk::RadioButton* edPS; - Gtk::RadioButton* edOther; - Gtk::FileChooserButton* darkFrameDir; - Gtk::FileChooserButton* flatFieldDir; - Gtk::FileChooserButton* clutsDir; - Gtk::Label *dfLabel; - Gtk::Label *ffLabel; - - Gtk::CheckButton* showDateTime; - Gtk::CheckButton* showBasicExif; - Gtk::CheckButton* showExpComp; - - Gtk::FileChooserButton* iccDir; - Gtk::FileChooserButton* monProfile; - Gtk::CheckButton* cbAutoMonProfile; - //Gtk::CheckButton* cbAutocielab; - Gtk::CheckButton* cbciecamfloat; - Gtk::CheckButton* cbdaubech; - Gtk::SpinButton* hlThresh; - Gtk::SpinButton* shThresh; - - Gtk::SpinButton* panFactor; - Gtk::CheckButton* rememberZoomPanCheckbutton; - - Gtk::ComboBoxText* intent; - Gtk::ComboBoxText* view; - Gtk::ComboBoxText* grey; - Gtk::ComboBoxText* greySc; - Gtk::ComboBoxText* dnv; - Gtk::ComboBoxText* dnti; - Gtk::ComboBoxText* dnaut; - Gtk::ComboBoxText* dnautsimpl; - Gtk::ComboBoxText* dnwavlev; - Gtk::ComboBoxText* dnliss; - - Gtk::Frame* waveletFrame; - Gtk::HBox* waveletTileSizeHBox; - Gtk::Label* waveletTileSizeLabel; - Gtk::ComboBoxText* waveletTileSizeCombo; - - Gtk::ComboBoxText* cprevdemo; - Gtk::CheckButton* ctiffserialize; - Gtk::ComboBoxText* curveBBoxPosC; - - Gtk::ComboBoxText* theme; - Gtk::CheckButton* slimUI; - Gtk::HBox* hbtheme; - Gtk::CheckButton* chUseSystemTheme; - Gtk::FontButton* fontbutton; - Gtk::ColorButton* butCropCol; - Gtk::ColorButton* butNavGuideCol; - - Gtk::SpinButton* maxThumbSize; +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef __PREFERENCES_H__ +#define __PREFERENCES_H__ + +#include +#include "adjuster.h" +#include "options.h" +#include +#include "rtwindow.h" + +class Preferences : public Gtk::Dialog, public ProfileStoreListener { + + class ExtensionColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn enabled; + Gtk::TreeModelColumn ext; + ExtensionColumns() { add(enabled); add(ext); } + }; + ExtensionColumns extensionColumns; + Glib::RefPtr extensionModel; + + + class BehavColumns : public Gtk::TreeModel::ColumnRecord { + public: + Gtk::TreeModelColumn label; + Gtk::TreeModelColumn badd; + Gtk::TreeModelColumn bset; + Gtk::TreeModelColumn visible; + Gtk::TreeModelColumn addsetid; + BehavColumns() { add(label); add(badd); add(bset); add(visible); add(addsetid); } + }; + Glib::RefPtr behModel; + BehavColumns behavColumns; + + + protected: + Splash* splash; + ProfileStoreComboBox* rprofiles; + Gtk::TreeIter currRawRow; // :) + ProfileStoreComboBox* iprofiles; + Gtk::TreeIter currImgRow; + Gtk::ComboBoxText* languages; + Gtk::CheckButton* ckbLangAutoDetect; + Gtk::Entry* dateformat; + Gtk::Entry* startupdir; + Gtk::RadioButton* sdcurrent; + Gtk::RadioButton* sdlast; + Gtk::RadioButton* sdhome; + Gtk::RadioButton* sdother; + Gtk::FileChooserButton* gimpDir; + Gtk::FileChooserButton* psDir; + Gtk::Entry* editorToSendTo; + Gtk::RadioButton* edGimp; + Gtk::RadioButton* edPS; + Gtk::RadioButton* edOther; + Gtk::FileChooserButton* darkFrameDir; + Gtk::FileChooserButton* flatFieldDir; + Gtk::FileChooserButton* clutsDir; + Gtk::Label *dfLabel; + Gtk::Label *ffLabel; + + Gtk::CheckButton* showDateTime; + Gtk::CheckButton* showBasicExif; + Gtk::CheckButton* showExpComp; + + Gtk::FileChooserButton* iccDir; + Gtk::FileChooserButton* monProfile; + Gtk::CheckButton* cbAutoMonProfile; + //Gtk::CheckButton* cbAutocielab; + Gtk::CheckButton* cbciecamfloat; + Gtk::CheckButton* cbdaubech; + Gtk::SpinButton* hlThresh; + Gtk::SpinButton* shThresh; + + Gtk::SpinButton* panFactor; + Gtk::CheckButton* rememberZoomPanCheckbutton; + + Gtk::ComboBoxText* intent; + Gtk::ComboBoxText* view; + Gtk::ComboBoxText* grey; + Gtk::ComboBoxText* greySc; + Gtk::ComboBoxText* dnv; + Gtk::ComboBoxText* dnti; + Gtk::ComboBoxText* dnaut; + Gtk::ComboBoxText* dnautsimpl; + Gtk::ComboBoxText* dnwavlev; + Gtk::ComboBoxText* dnliss; + + Gtk::Frame* waveletFrame; + Gtk::HBox* waveletTileSizeHBox; + Gtk::Label* waveletTileSizeLabel; + Gtk::ComboBoxText* waveletTileSizeCombo; + + Gtk::ComboBoxText* cprevdemo; + Gtk::CheckButton* ctiffserialize; + Gtk::ComboBoxText* curveBBoxPosC; + + Gtk::ComboBoxText* theme; + Gtk::CheckButton* slimUI; + Gtk::HBox* hbtheme; + Gtk::CheckButton* chUseSystemTheme; + Gtk::FontButton* fontbutton; + Gtk::ColorButton* butCropCol; + Gtk::ColorButton* butNavGuideCol; + + Gtk::SpinButton* maxThumbSize; Gtk::SpinButton* maxCacheEntries; - Gtk::SpinButton* maxRecentFolders; - Gtk::Button* clearThumbnails; - Gtk::Button* clearProfiles; - Gtk::Button* clearAll; - Gtk::Entry* extension; - Gtk::TreeView* extensions; - Gtk::Button* addExt; - Gtk::Button* delExt; - Gtk::CheckButton* overlayedFileNames; - Gtk::CheckButton* filmStripOverlayedFileNames; - Gtk::CheckButton* sameThumbSize; - - Gtk::SpinButton* rgbDenoiseTreadLimitSB; - Gtk::SpinButton* clutCacheSizeSB; - Gtk::SpinButton* maxInspectorBuffersSB; - - Gtk::CheckButton* ckbmenuGroupRank; - Gtk::CheckButton* ckbmenuGroupLabel; - Gtk::CheckButton* ckbmenuGroupFileOperations; - Gtk::CheckButton* ckbmenuGroupProfileOperations; - Gtk::CheckButton* ckbmenuGroupExtProg; - - Gtk::Button* behAddAll; - Gtk::Button* behSetAll; - Gtk::CheckButton* chOverwriteOutputFile; - - Gtk::CheckButton* saveParamsFile; - Gtk::CheckButton* saveParamsCache; - Gtk::CheckButton* useBundledProfiles; - Gtk::ComboBoxText* loadParamsPreference; - Gtk::ComboBoxText* editorLayout; - RTWindow* parent; - - Gtk::CheckButton* ckbSndEnable; - Gtk::Entry* txtSndBatchQueueDone; - Gtk::Entry* txtSndLngEditProcDone; - Gtk::SpinButton* spbSndLngEditProcDoneSecs; - - Gtk::CheckButton* ckbTunnelMetaData; - Gtk::CheckButton* ckbInternalThumbIfUntouched; - - Gtk::Entry* txtCustProfBuilderPath; - Gtk::ComboBoxText* custProfBuilderLabelType; - - Gtk::CheckButton* ckbHistogramPositionLeft; - Gtk::CheckButton* ckbHistogramWorking; - Gtk::CheckButton* ckbFileBrowserToolbarSingleRow; - Gtk::CheckButton* ckbShowFilmStripToolBar; - Gtk::CheckButton* ckbHideTPVScrollbar; - Gtk::CheckButton* ckbUseIconNoText; - - Glib::ustring storedValueRaw; - Glib::ustring storedValueImg; - - Options moptions; - sigc::connection tconn, sconn, fconn, usethcon, addc, setc, dfconn, ffconn, bpconn, rpconn, ipconn; - sigc::connection autoMonProfileConn, sndEnableConn, langAutoDetectConn, autocielabConn; - Glib::ustring initialTheme; - Glib::ustring initialFont; - - bool oldSlimUI; - - void fillPreferences (); - void storePreferences (); - void parseDir (Glib::ustring dirname, std::vector& items, Glib::ustring ext); - void updateDFinfos (); - void updateFFinfos (); - void workflowUpdate(); - void themeChanged (); - void useThemeChanged(); - void fontChanged (); - void forRAWComboChanged (); - void forImageComboChanged (); - void layoutComboChanged (); - void bundledProfilesChanged(); - void switchThemeTo (Glib::ustring newTheme, bool slimInterface); - void switchFontTo (Glib::ustring newFont); - bool splashClosed(GdkEventAny* event); - - void appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, int id, bool set); - - Gtk::Widget* getProcParamsPanel (); - Gtk::Widget* getColorManagementPanel (); - Gtk::Widget* getFileBrowserPanel (); - Gtk::Widget* getGeneralPanel (); - Gtk::Widget* getBatchProcPanel (); - Gtk::Widget* getPerformancePanel (); - Gtk::Widget* getSoundPanel (); - - public: - Preferences (RTWindow *rtwindow); - ~Preferences (); - - void savePressed (); - void loadPressed (); - void okPressed (); - void cancelPressed (); - void aboutPressed (); - void autoMonProfileToggled (); - void sndEnableToggled (); - void langAutoDetectToggled (); - void autocielabToggled (); - - void selectStartupDir (); - void addExtPressed (); - void delExtPressed (); - void darkFrameChanged (); - void flatFieldChanged (); - void clearProfilesPressed (); - void clearThumbImagesPressed (); - void clearAllPressed (); - - void behAddRadioToggled (const Glib::ustring& path); - void behSetRadioToggled (const Glib::ustring& path); - void behAddAllPressed (); - void behSetAllPressed (); - - virtual void storeCurrentValue(); - virtual void updateProfileList(); - virtual void restoreValue(); - -// void selectICCProfileDir (); -// void selectMonitorProfile (); -}; - -#endif + Gtk::SpinButton* maxRecentFolders; + Gtk::Button* clearThumbnails; + Gtk::Button* clearProfiles; + Gtk::Button* clearAll; + Gtk::Entry* extension; + Gtk::TreeView* extensions; + Gtk::Button* addExt; + Gtk::Button* delExt; + Gtk::CheckButton* overlayedFileNames; + Gtk::CheckButton* filmStripOverlayedFileNames; + Gtk::CheckButton* sameThumbSize; + + Gtk::SpinButton* rgbDenoiseTreadLimitSB; + Gtk::SpinButton* clutCacheSizeSB; + Gtk::SpinButton* maxInspectorBuffersSB; + + Gtk::CheckButton* ckbmenuGroupRank; + Gtk::CheckButton* ckbmenuGroupLabel; + Gtk::CheckButton* ckbmenuGroupFileOperations; + Gtk::CheckButton* ckbmenuGroupProfileOperations; + Gtk::CheckButton* ckbmenuGroupExtProg; + + Gtk::Button* behAddAll; + Gtk::Button* behSetAll; + Gtk::CheckButton* chOverwriteOutputFile; + + Gtk::CheckButton* saveParamsFile; + Gtk::CheckButton* saveParamsCache; + Gtk::CheckButton* useBundledProfiles; + Gtk::ComboBoxText* loadParamsPreference; + Gtk::ComboBoxText* editorLayout; + RTWindow* parent; + + Gtk::CheckButton* ckbSndEnable; + Gtk::Entry* txtSndBatchQueueDone; + Gtk::Entry* txtSndLngEditProcDone; + Gtk::SpinButton* spbSndLngEditProcDoneSecs; + + Gtk::CheckButton* ckbTunnelMetaData; + Gtk::CheckButton* ckbInternalThumbIfUntouched; + + Gtk::Entry* txtCustProfBuilderPath; + Gtk::ComboBoxText* custProfBuilderLabelType; + + Gtk::CheckButton* ckbHistogramPositionLeft; + Gtk::CheckButton* ckbHistogramWorking; + Gtk::CheckButton* ckbFileBrowserToolbarSingleRow; + Gtk::CheckButton* ckbShowFilmStripToolBar; + Gtk::CheckButton* ckbHideTPVScrollbar; + Gtk::CheckButton* ckbUseIconNoText; + + Glib::ustring storedValueRaw; + Glib::ustring storedValueImg; + + Options moptions; + sigc::connection tconn, sconn, fconn, usethcon, addc, setc, dfconn, ffconn, bpconn, rpconn, ipconn; + sigc::connection autoMonProfileConn, sndEnableConn, langAutoDetectConn, autocielabConn; + Glib::ustring initialTheme; + Glib::ustring initialFont; + + bool oldSlimUI; + + void fillPreferences (); + void storePreferences (); + void parseDir (Glib::ustring dirname, std::vector& items, Glib::ustring ext); + void updateDFinfos (); + void updateFFinfos (); + void workflowUpdate(); + void themeChanged (); + void useThemeChanged(); + void fontChanged (); + void forRAWComboChanged (); + void forImageComboChanged (); + void layoutComboChanged (); + void bundledProfilesChanged(); + void switchThemeTo (Glib::ustring newTheme, bool slimInterface); + void switchFontTo (Glib::ustring newFont); + bool splashClosed(GdkEventAny* event); + + void appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, int id, bool set); + + Gtk::Widget* getProcParamsPanel (); + Gtk::Widget* getColorManagementPanel (); + Gtk::Widget* getFileBrowserPanel (); + Gtk::Widget* getGeneralPanel (); + Gtk::Widget* getBatchProcPanel (); + Gtk::Widget* getPerformancePanel (); + Gtk::Widget* getSoundPanel (); + + public: + Preferences (RTWindow *rtwindow); + ~Preferences (); + + void savePressed (); + void loadPressed (); + void okPressed (); + void cancelPressed (); + void aboutPressed (); + void autoMonProfileToggled (); + void sndEnableToggled (); + void langAutoDetectToggled (); + void autocielabToggled (); + + void selectStartupDir (); + void addExtPressed (); + void delExtPressed (); + void darkFrameChanged (); + void flatFieldChanged (); + void clearProfilesPressed (); + void clearThumbImagesPressed (); + void clearAllPressed (); + + void behAddRadioToggled (const Glib::ustring& path); + void behSetRadioToggled (const Glib::ustring& path); + void behAddAllPressed (); + void behSetAllPressed (); + + virtual void storeCurrentValue(); + virtual void updateProfileList(); + virtual void restoreValue(); + +// void selectICCProfileDir (); +// void selectMonitorProfile (); +}; + +#endif diff --git a/rtgui/preprocess.h b/rtgui/preprocess.h index 10d942c44..d99973296 100644 --- a/rtgui/preprocess.h +++ b/rtgui/preprocess.h @@ -1,57 +1,57 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _PREPROCESS_H_ -#define _PREPROCESS_H_ - -#include -//#include "adjuster.h" -#include "toolpanel.h" -#include "adjuster.h" -#include "guiutils.h" -#include "../rtengine/rawimage.h" - -class PreProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { - - protected: - Gtk::CheckButton* hotPixel; - Gtk::CheckButton* deadPixel; - bool lastHot,lastDead; - sigc::connection hpixelconn; - sigc::connection dpixelconn; - Adjuster* hdThreshold; - public: - - PreProcess (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - //void setBatchMode (bool batchMode); - //void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - - void hotPixelChanged(); - void deadPixelChanged(); - void adjusterChanged (Adjuster* a, double newval); - - - //void adjusterChanged (Adjuster* a, double newval); - //void setAdjusterBehavior (bool linedenoiseadd, bool greenequiladd); - //void trimValues (rtengine::procparams::ProcParams* pp); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _PREPROCESS_H_ +#define _PREPROCESS_H_ + +#include +//#include "adjuster.h" +#include "toolpanel.h" +#include "adjuster.h" +#include "guiutils.h" +#include "../rtengine/rawimage.h" + +class PreProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { + + protected: + Gtk::CheckButton* hotPixel; + Gtk::CheckButton* deadPixel; + bool lastHot,lastDead; + sigc::connection hpixelconn; + sigc::connection dpixelconn; + Adjuster* hdThreshold; + public: + + PreProcess (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + //void setBatchMode (bool batchMode); + //void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + + void hotPixelChanged(); + void deadPixelChanged(); + void adjusterChanged (Adjuster* a, double newval); + + + //void adjusterChanged (Adjuster* a, double newval); + //void setAdjusterBehavior (bool linedenoiseadd, bool greenequiladd); + //void trimValues (rtengine::procparams::ProcParams* pp); +}; + +#endif diff --git a/rtgui/previewmodepanel.cc b/rtgui/previewmodepanel.cc index 10225c22d..f135b05db 100644 --- a/rtgui/previewmodepanel.cc +++ b/rtgui/previewmodepanel.cc @@ -1,212 +1,212 @@ -/* - * This file is part of RawTherapee. - * - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "previewmodepanel.h" -#include "options.h" -#include "multilangmgr.h" -#include "imagearea.h" -#include "rtimage.h" - -PreviewModePanel::PreviewModePanel (ImageArea* ia) : imageArea(ia) { - - iR = new RTImage ("previewmodeR-on.png"); - iG = new RTImage ("previewmodeG-on.png"); - iB = new RTImage ("previewmodeB-on.png"); - iL = new RTImage ("previewmodeL-on.png"); - iF = new RTImage ("previewmodeF-on.png"); - iBC0= new RTImage ("previewmodeBC0-on.png"); - iBC1= new RTImage ("previewmodeBC1-on.png"); - iBC2= new RTImage ("previewmodeBC2-on.png"); - - igR = new RTImage ("previewmodeR-off.png"); - igG = new RTImage ("previewmodeG-off.png"); - igB = new RTImage ("previewmodeB-off.png"); - igL = new RTImage ("previewmodeL-off.png"); - igF = new RTImage ("previewmodeF-off.png"); - igBC0= new RTImage ("previewmodeBC0-off.png"); - igBC1= new RTImage ("previewmodeBC1-off.png"); - igBC2= new RTImage ("previewmodeBC2-off.png"); - - backColor0 = Gtk::manage (new Gtk::ToggleButton ()); - backColor0->set_relief(Gtk::RELIEF_NONE); - backColor0->set_tooltip_markup (M("MAIN_TOOLTIP_BACKCOLOR0")); - backColor0->set_image(options.bgcolor==0?*iBC0:*igBC0); - - backColor1 = Gtk::manage (new Gtk::ToggleButton ()); - backColor1->set_relief(Gtk::RELIEF_NONE); - backColor1->set_tooltip_markup (M("MAIN_TOOLTIP_BACKCOLOR1")); - backColor1->set_image(options.bgcolor==1?*iBC1:*igBC1); - - backColor2 = Gtk::manage (new Gtk::ToggleButton ()); - backColor2->set_relief(Gtk::RELIEF_NONE); - backColor2->set_tooltip_markup (M("MAIN_TOOLTIP_BACKCOLOR2")); - backColor2->set_image(options.bgcolor==2?*iBC2:*igBC2); - - previewR = Gtk::manage (new Gtk::ToggleButton ()); - previewR->set_relief(Gtk::RELIEF_NONE); - previewR->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWR")); - previewR->set_image(*igR); - - previewG = Gtk::manage (new Gtk::ToggleButton ()); - previewG->set_relief(Gtk::RELIEF_NONE); - previewG->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWG")); - previewG->set_image(*igG); - - previewB = Gtk::manage (new Gtk::ToggleButton ()); - previewB->set_relief(Gtk::RELIEF_NONE); - previewB->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWB")); - previewB->set_image(*igB); - - previewL = Gtk::manage (new Gtk::ToggleButton ()); - previewL->set_relief(Gtk::RELIEF_NONE); - previewL->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWL")); - previewL->set_image(*igL); - - previewFocusMask = Gtk::manage (new Gtk::ToggleButton ()); - previewFocusMask->set_relief(Gtk::RELIEF_NONE); - previewFocusMask->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWFOCUSMASK")); - previewFocusMask->set_image(*igF); - - previewR->set_active (false); - previewG->set_active (false); - previewB->set_active (false); - previewL->set_active (false); - previewFocusMask->set_active (false); - - backColor0->set_active (options.bgcolor==0?true:false); - backColor1->set_active (options.bgcolor==1?true:false); - backColor2->set_active (options.bgcolor==2?true:false); - - vbbackColor = Gtk::manage (new Gtk::VBox ()); - vbbackColor->set_border_width (0); - vbbackColor->pack_start (*backColor0, Gtk::PACK_SHRINK, 0); - vbbackColor->pack_start (*backColor1, Gtk::PACK_SHRINK, 0); - vbbackColor->pack_start (*backColor2, Gtk::PACK_SHRINK, 0); - pack_start (*vbbackColor, Gtk::PACK_SHRINK, 0); - - pack_start (*previewR, Gtk::PACK_SHRINK, 0); - pack_start (*previewG, Gtk::PACK_SHRINK, 0); - pack_start (*previewB, Gtk::PACK_SHRINK, 0); - pack_start (*previewL, Gtk::PACK_SHRINK, 0); - pack_start (*previewFocusMask, Gtk::PACK_SHRINK, 0); - - connR = previewR->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewR) ); - connG = previewG->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewG) ); - connB = previewB->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewB) ); - connL = previewL->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewL) ); - connFocusMask = previewFocusMask->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewFocusMask) ); - - connbackColor0 = backColor0->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled_backColor),backColor0) ); - connbackColor1 = backColor1->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled_backColor),backColor1) ); - connbackColor2 = backColor2->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled_backColor),backColor2) ); - - //show_all (); -} - -PreviewModePanel::~PreviewModePanel (){ - delete iR; - delete iG; - delete iB; - delete iL; - delete iF; - delete iBC0; - delete iBC1; - delete iBC2; - delete igR; - delete igG; - delete igB; - delete igL; - delete igF; - delete igBC0; - delete igBC1; - delete igBC2; -} -//toggle Functions below are for shortcuts -void PreviewModePanel::toggleR () { - previewR->set_active(!previewR->get_active()); -} -void PreviewModePanel::toggleG () { - previewG->set_active(!previewG->get_active()); -} -void PreviewModePanel::toggleB () { - previewB->set_active(!previewB->get_active()); -} -void PreviewModePanel::toggleL () { - previewL->set_active(!previewL->get_active()); -} -void PreviewModePanel::toggleFocusMask () { - previewFocusMask->set_active(!previewFocusMask->get_active()); -} - -void PreviewModePanel::togglebackColor0 () { - backColor0->set_active(!backColor0->get_active()); -} -void PreviewModePanel::togglebackColor1 () { - backColor1->set_active(!backColor1->get_active()); -} -void PreviewModePanel::togglebackColor2 () { - backColor2->set_active(!backColor2->get_active()); -} - -void PreviewModePanel::buttonToggled (Gtk::ToggleButton* tbpreview) { - - connR.block(true); - connG.block(true); - connB.block(true); - connL.block(true); - connFocusMask.block(true); - - // control state of the buttons - // only 0 or 1 button at a time can remain pressed - if (tbpreview!=previewR) previewR->set_active(false); - if (tbpreview!=previewG) previewG->set_active(false); - if (tbpreview!=previewB) previewB->set_active(false); - if (tbpreview!=previewL) previewL->set_active(false); - if (tbpreview!=previewFocusMask) previewFocusMask->set_active(false); - - // set image based on button's state - previewR->set_image(previewR->get_active()?*iR:*igR); - previewG->set_image(previewG->get_active()?*iG:*igG); - previewB->set_image(previewB->get_active()?*iB:*igB); - previewL->set_image(previewL->get_active()?*iL:*igL); - previewFocusMask->set_image(previewFocusMask->get_active()?*iF:*igF); - - connR.block(false); - connG.block(false); - connB.block(false); - connL.block(false); - connFocusMask.block(false); - - imageArea->queue_draw (); - - // this will redraw the linked Before image area - // which is set when before/after view is enabled - if (imageArea->iLinkedImageArea!=NULL) - imageArea->iLinkedImageArea->queue_draw (); -} - -int PreviewModePanel::GetbackColor(){ - int backColor; - if (backColor0->get_active ()) backColor=0; - if (backColor1->get_active ()) backColor=1; - if (backColor2->get_active ()) backColor=2; - - return backColor; -} +/* + * This file is part of RawTherapee. + * + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "previewmodepanel.h" +#include "options.h" +#include "multilangmgr.h" +#include "imagearea.h" +#include "rtimage.h" + +PreviewModePanel::PreviewModePanel (ImageArea* ia) : imageArea(ia) { + + iR = new RTImage ("previewmodeR-on.png"); + iG = new RTImage ("previewmodeG-on.png"); + iB = new RTImage ("previewmodeB-on.png"); + iL = new RTImage ("previewmodeL-on.png"); + iF = new RTImage ("previewmodeF-on.png"); + iBC0= new RTImage ("previewmodeBC0-on.png"); + iBC1= new RTImage ("previewmodeBC1-on.png"); + iBC2= new RTImage ("previewmodeBC2-on.png"); + + igR = new RTImage ("previewmodeR-off.png"); + igG = new RTImage ("previewmodeG-off.png"); + igB = new RTImage ("previewmodeB-off.png"); + igL = new RTImage ("previewmodeL-off.png"); + igF = new RTImage ("previewmodeF-off.png"); + igBC0= new RTImage ("previewmodeBC0-off.png"); + igBC1= new RTImage ("previewmodeBC1-off.png"); + igBC2= new RTImage ("previewmodeBC2-off.png"); + + backColor0 = Gtk::manage (new Gtk::ToggleButton ()); + backColor0->set_relief(Gtk::RELIEF_NONE); + backColor0->set_tooltip_markup (M("MAIN_TOOLTIP_BACKCOLOR0")); + backColor0->set_image(options.bgcolor==0?*iBC0:*igBC0); + + backColor1 = Gtk::manage (new Gtk::ToggleButton ()); + backColor1->set_relief(Gtk::RELIEF_NONE); + backColor1->set_tooltip_markup (M("MAIN_TOOLTIP_BACKCOLOR1")); + backColor1->set_image(options.bgcolor==1?*iBC1:*igBC1); + + backColor2 = Gtk::manage (new Gtk::ToggleButton ()); + backColor2->set_relief(Gtk::RELIEF_NONE); + backColor2->set_tooltip_markup (M("MAIN_TOOLTIP_BACKCOLOR2")); + backColor2->set_image(options.bgcolor==2?*iBC2:*igBC2); + + previewR = Gtk::manage (new Gtk::ToggleButton ()); + previewR->set_relief(Gtk::RELIEF_NONE); + previewR->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWR")); + previewR->set_image(*igR); + + previewG = Gtk::manage (new Gtk::ToggleButton ()); + previewG->set_relief(Gtk::RELIEF_NONE); + previewG->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWG")); + previewG->set_image(*igG); + + previewB = Gtk::manage (new Gtk::ToggleButton ()); + previewB->set_relief(Gtk::RELIEF_NONE); + previewB->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWB")); + previewB->set_image(*igB); + + previewL = Gtk::manage (new Gtk::ToggleButton ()); + previewL->set_relief(Gtk::RELIEF_NONE); + previewL->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWL")); + previewL->set_image(*igL); + + previewFocusMask = Gtk::manage (new Gtk::ToggleButton ()); + previewFocusMask->set_relief(Gtk::RELIEF_NONE); + previewFocusMask->set_tooltip_markup (M("MAIN_TOOLTIP_PREVIEWFOCUSMASK")); + previewFocusMask->set_image(*igF); + + previewR->set_active (false); + previewG->set_active (false); + previewB->set_active (false); + previewL->set_active (false); + previewFocusMask->set_active (false); + + backColor0->set_active (options.bgcolor==0?true:false); + backColor1->set_active (options.bgcolor==1?true:false); + backColor2->set_active (options.bgcolor==2?true:false); + + vbbackColor = Gtk::manage (new Gtk::VBox ()); + vbbackColor->set_border_width (0); + vbbackColor->pack_start (*backColor0, Gtk::PACK_SHRINK, 0); + vbbackColor->pack_start (*backColor1, Gtk::PACK_SHRINK, 0); + vbbackColor->pack_start (*backColor2, Gtk::PACK_SHRINK, 0); + pack_start (*vbbackColor, Gtk::PACK_SHRINK, 0); + + pack_start (*previewR, Gtk::PACK_SHRINK, 0); + pack_start (*previewG, Gtk::PACK_SHRINK, 0); + pack_start (*previewB, Gtk::PACK_SHRINK, 0); + pack_start (*previewL, Gtk::PACK_SHRINK, 0); + pack_start (*previewFocusMask, Gtk::PACK_SHRINK, 0); + + connR = previewR->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewR) ); + connG = previewG->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewG) ); + connB = previewB->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewB) ); + connL = previewL->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewL) ); + connFocusMask = previewFocusMask->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled),previewFocusMask) ); + + connbackColor0 = backColor0->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled_backColor),backColor0) ); + connbackColor1 = backColor1->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled_backColor),backColor1) ); + connbackColor2 = backColor2->signal_toggled().connect( sigc::bind(sigc::mem_fun(*this, &PreviewModePanel::buttonToggled_backColor),backColor2) ); + + //show_all (); +} + +PreviewModePanel::~PreviewModePanel (){ + delete iR; + delete iG; + delete iB; + delete iL; + delete iF; + delete iBC0; + delete iBC1; + delete iBC2; + delete igR; + delete igG; + delete igB; + delete igL; + delete igF; + delete igBC0; + delete igBC1; + delete igBC2; +} +//toggle Functions below are for shortcuts +void PreviewModePanel::toggleR () { + previewR->set_active(!previewR->get_active()); +} +void PreviewModePanel::toggleG () { + previewG->set_active(!previewG->get_active()); +} +void PreviewModePanel::toggleB () { + previewB->set_active(!previewB->get_active()); +} +void PreviewModePanel::toggleL () { + previewL->set_active(!previewL->get_active()); +} +void PreviewModePanel::toggleFocusMask () { + previewFocusMask->set_active(!previewFocusMask->get_active()); +} + +void PreviewModePanel::togglebackColor0 () { + backColor0->set_active(!backColor0->get_active()); +} +void PreviewModePanel::togglebackColor1 () { + backColor1->set_active(!backColor1->get_active()); +} +void PreviewModePanel::togglebackColor2 () { + backColor2->set_active(!backColor2->get_active()); +} + +void PreviewModePanel::buttonToggled (Gtk::ToggleButton* tbpreview) { + + connR.block(true); + connG.block(true); + connB.block(true); + connL.block(true); + connFocusMask.block(true); + + // control state of the buttons + // only 0 or 1 button at a time can remain pressed + if (tbpreview!=previewR) previewR->set_active(false); + if (tbpreview!=previewG) previewG->set_active(false); + if (tbpreview!=previewB) previewB->set_active(false); + if (tbpreview!=previewL) previewL->set_active(false); + if (tbpreview!=previewFocusMask) previewFocusMask->set_active(false); + + // set image based on button's state + previewR->set_image(previewR->get_active()?*iR:*igR); + previewG->set_image(previewG->get_active()?*iG:*igG); + previewB->set_image(previewB->get_active()?*iB:*igB); + previewL->set_image(previewL->get_active()?*iL:*igL); + previewFocusMask->set_image(previewFocusMask->get_active()?*iF:*igF); + + connR.block(false); + connG.block(false); + connB.block(false); + connL.block(false); + connFocusMask.block(false); + + imageArea->queue_draw (); + + // this will redraw the linked Before image area + // which is set when before/after view is enabled + if (imageArea->iLinkedImageArea!=NULL) + imageArea->iLinkedImageArea->queue_draw (); +} + +int PreviewModePanel::GetbackColor(){ + int backColor; + if (backColor0->get_active ()) backColor=0; + if (backColor1->get_active ()) backColor=1; + if (backColor2->get_active ()) backColor=2; + + return backColor; +} void PreviewModePanel::togglebackColor(){ int backColor = GetbackColor(); @@ -217,37 +217,37 @@ void PreviewModePanel::togglebackColor(){ else togglebackColor0(); } - -void PreviewModePanel::buttonToggled_backColor (Gtk::ToggleButton* tbbackColor) { - - connbackColor0.block(true); - connbackColor1.block(true); - connbackColor2.block(true); - - // control the state of the buttons - // Exactly 1 button at a time must remain pressed - if (tbbackColor==backColor0 && !backColor0->get_active()) backColor0->set_active(true); - if (tbbackColor==backColor1 && !backColor1->get_active()) backColor1->set_active(true); - if (tbbackColor==backColor2 && !backColor2->get_active()) backColor2->set_active(true); - - if (tbbackColor!=backColor0) backColor0->set_active(false); - if (tbbackColor!=backColor1) backColor1->set_active(false); - if (tbbackColor!=backColor2) backColor2->set_active(false); - - // set image based on button's state - backColor0->set_image(backColor0->get_active()?*iBC0:*igBC0); - backColor1->set_image(backColor1->get_active()?*iBC1:*igBC1); - backColor2->set_image(backColor2->get_active()?*iBC2:*igBC2); - - connbackColor0.block(false); - connbackColor1.block(false); - connbackColor2.block(false); - - //TODO not sure if queue_draw is necessary, but will need to reach to backColor of the Before view - imageArea->queue_draw (); - - // this will redraw the linked Before image area - // which is set when before/after view is enabled - if (imageArea->iLinkedImageArea!=NULL) - imageArea->iLinkedImageArea->queue_draw (); -} + +void PreviewModePanel::buttonToggled_backColor (Gtk::ToggleButton* tbbackColor) { + + connbackColor0.block(true); + connbackColor1.block(true); + connbackColor2.block(true); + + // control the state of the buttons + // Exactly 1 button at a time must remain pressed + if (tbbackColor==backColor0 && !backColor0->get_active()) backColor0->set_active(true); + if (tbbackColor==backColor1 && !backColor1->get_active()) backColor1->set_active(true); + if (tbbackColor==backColor2 && !backColor2->get_active()) backColor2->set_active(true); + + if (tbbackColor!=backColor0) backColor0->set_active(false); + if (tbbackColor!=backColor1) backColor1->set_active(false); + if (tbbackColor!=backColor2) backColor2->set_active(false); + + // set image based on button's state + backColor0->set_image(backColor0->get_active()?*iBC0:*igBC0); + backColor1->set_image(backColor1->get_active()?*iBC1:*igBC1); + backColor2->set_image(backColor2->get_active()?*iBC2:*igBC2); + + connbackColor0.block(false); + connbackColor1.block(false); + connbackColor2.block(false); + + //TODO not sure if queue_draw is necessary, but will need to reach to backColor of the Before view + imageArea->queue_draw (); + + // this will redraw the linked Before image area + // which is set when before/after view is enabled + if (imageArea->iLinkedImageArea!=NULL) + imageArea->iLinkedImageArea->queue_draw (); +} diff --git a/rtgui/previewmodepanel.h b/rtgui/previewmodepanel.h index 38292c95d..3875ec49e 100644 --- a/rtgui/previewmodepanel.h +++ b/rtgui/previewmodepanel.h @@ -1,76 +1,76 @@ -/* - * This file is part of RawTherapee. - * - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _PREVIEWMODEPANEL_ -#define _PREVIEWMODEPANEL_ - -#include -#include "adjuster.h"//dev - -class ImageArea; -class PreviewModePanel : public Gtk::HBox { - - protected: - Gtk::ToggleButton* previewR; - Gtk::ToggleButton* previewG; - Gtk::ToggleButton* previewB; - Gtk::ToggleButton* previewL; - Gtk::ToggleButton* previewFocusMask; - Gtk::ToggleButton* backColor0; - Gtk::ToggleButton* backColor1; - Gtk::ToggleButton* backColor2; - Gtk::VBox* vbbackColor; - ImageArea* imageArea; - - Gtk::Image* iR, *igR; - Gtk::Image* iG, *igG; - Gtk::Image* iB, *igB; - Gtk::Image* iL, *igL; - Gtk::Image* iF, *igF; - Gtk::Image* iBC0, *igBC0; - Gtk::Image* iBC1, *igBC1; - Gtk::Image* iBC2, *igBC2; - - public: - PreviewModePanel (ImageArea* ia); - ~PreviewModePanel(); - - void toggleR (); - void toggleG (); - void toggleB (); - void toggleL (); - void toggleFocusMask (); - void togglebackColor0(); - void togglebackColor1(); - void togglebackColor2(); - void togglebackColor(); - - sigc::connection connR, connB, connG, connL, connFocusMask, connbackColor0, connbackColor1, connbackColor2; - - void buttonToggled(Gtk::ToggleButton* tbpreview); - void buttonToggled_backColor(Gtk::ToggleButton* tbbackColor); - - bool showR () { return previewR->get_active (); } - bool showG () { return previewG->get_active (); } - bool showB () { return previewB->get_active (); } - bool showL () { return previewL->get_active (); } - bool showFocusMask () { return previewFocusMask->get_active (); } +/* + * This file is part of RawTherapee. + * + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _PREVIEWMODEPANEL_ +#define _PREVIEWMODEPANEL_ + +#include +#include "adjuster.h"//dev + +class ImageArea; +class PreviewModePanel : public Gtk::HBox { + + protected: + Gtk::ToggleButton* previewR; + Gtk::ToggleButton* previewG; + Gtk::ToggleButton* previewB; + Gtk::ToggleButton* previewL; + Gtk::ToggleButton* previewFocusMask; + Gtk::ToggleButton* backColor0; + Gtk::ToggleButton* backColor1; + Gtk::ToggleButton* backColor2; + Gtk::VBox* vbbackColor; + ImageArea* imageArea; + + Gtk::Image* iR, *igR; + Gtk::Image* iG, *igG; + Gtk::Image* iB, *igB; + Gtk::Image* iL, *igL; + Gtk::Image* iF, *igF; + Gtk::Image* iBC0, *igBC0; + Gtk::Image* iBC1, *igBC1; + Gtk::Image* iBC2, *igBC2; + + public: + PreviewModePanel (ImageArea* ia); + ~PreviewModePanel(); + + void toggleR (); + void toggleG (); + void toggleB (); + void toggleL (); + void toggleFocusMask (); + void togglebackColor0(); + void togglebackColor1(); + void togglebackColor2(); + void togglebackColor(); + + sigc::connection connR, connB, connG, connL, connFocusMask, connbackColor0, connbackColor1, connbackColor2; + + void buttonToggled(Gtk::ToggleButton* tbpreview); + void buttonToggled_backColor(Gtk::ToggleButton* tbbackColor); + + bool showR () { return previewR->get_active (); } + bool showG () { return previewG->get_active (); } + bool showB () { return previewB->get_active (); } + bool showL () { return previewL->get_active (); } + bool showFocusMask () { return previewFocusMask->get_active (); } int GetbackColor(); - -}; - -#endif + +}; + +#endif diff --git a/rtgui/previewwindow.cc b/rtgui/previewwindow.cc index 6038bb018..399872307 100644 --- a/rtgui/previewwindow.cc +++ b/rtgui/previewwindow.cc @@ -1,221 +1,221 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "previewwindow.h" -#include "guiutils.h" -#include "imagearea.h" -#include "cursormanager.h" - -PreviewWindow::PreviewWindow () : previewHandler(NULL), mainCropWin(NULL), imageArea(NULL), imgX(0), imgY(0), imgW(0), imgH(0), zoom(0.0), isMoving(false), needsUpdate(false) { - - rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &PreviewWindow::on_resized) ); -} - -void PreviewWindow::on_realize () { - - Gtk::DrawingArea::on_realize (); - add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); -} - -void PreviewWindow::getObservedFrameArea (int& x, int& y, int& w, int& h) { - - if (mainCropWin) { - int cropX, cropY, cropW, cropH; +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "previewwindow.h" +#include "guiutils.h" +#include "imagearea.h" +#include "cursormanager.h" + +PreviewWindow::PreviewWindow () : previewHandler(NULL), mainCropWin(NULL), imageArea(NULL), imgX(0), imgY(0), imgW(0), imgH(0), zoom(0.0), isMoving(false), needsUpdate(false) { + + rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &PreviewWindow::on_resized) ); +} + +void PreviewWindow::on_realize () { + + Gtk::DrawingArea::on_realize (); + add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); +} + +void PreviewWindow::getObservedFrameArea (int& x, int& y, int& w, int& h) { + + if (mainCropWin) { + int cropX, cropY, cropW, cropH; mainCropWin->getCropRectangle (cropX, cropY, cropW, cropH); - // translate it to screen coordinates - x = imgX + round(cropX*zoom); - y = imgY + round(cropY*zoom); - w = round(cropW * zoom); - h = round(cropH * zoom); - } -} - -void PreviewWindow::updatePreviewImage () { - - int W = get_width(), H = get_height(); - Glib::RefPtr wind = get_window(); + // translate it to screen coordinates + x = imgX + round(cropX*zoom); + y = imgY + round(cropY*zoom); + w = round(cropW * zoom); + h = round(cropH * zoom); + } +} + +void PreviewWindow::updatePreviewImage () { + + int W = get_width(), H = get_height(); + Glib::RefPtr wind = get_window(); if( ! wind ) { - needsUpdate = true; + needsUpdate = true; return; - } - backBuffer = Gdk::Pixmap::create (wind, W, H, -1); - backBuffer->draw_rectangle (get_style()->get_base_gc(Gtk::STATE_NORMAL), true, 0, 0, W, H); - if (previewHandler) { - Glib::RefPtr resPixbuf = previewHandler->getRoughImage (W, H, zoom); - if (resPixbuf) { - imgW = resPixbuf->get_width(); - imgH = resPixbuf->get_height(); - imgX = (W-imgW)/2; - imgY = (H-imgH)/2; - backBuffer->draw_pixbuf (get_style()->get_base_gc(Gtk::STATE_NORMAL), resPixbuf, 0, 0, imgX, imgY, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0); - Cairo::RefPtr cr = backBuffer->create_cairo_context(); - if (previewHandler->getCropParams().enabled) - drawCrop (cr, imgX, imgY, imgW, imgH, 0, 0, zoom, previewHandler->getCropParams(), true, false); - } - } -} - -void PreviewWindow::setPreviewHandler (PreviewHandler* ph) { - - previewHandler = ph; - if (previewHandler) - previewHandler->addPreviewImageListener (this); -} - -void PreviewWindow::on_resized (Gtk::Allocation& req) { - - updatePreviewImage (); - queue_draw (); -} - -bool PreviewWindow::on_expose_event (GdkEventExpose* event) { - - if (backBuffer) { - Glib::RefPtr window = get_window(); - - int bufferW, bufferH; - backBuffer->get_size (bufferW, bufferH); - - if (!mainCropWin && imageArea) { - mainCropWin = imageArea->getMainCropWindow (); - if (mainCropWin) - mainCropWin->addCropWindowListener (this); - } - + } + backBuffer = Gdk::Pixmap::create (wind, W, H, -1); + backBuffer->draw_rectangle (get_style()->get_base_gc(Gtk::STATE_NORMAL), true, 0, 0, W, H); + if (previewHandler) { + Glib::RefPtr resPixbuf = previewHandler->getRoughImage (W, H, zoom); + if (resPixbuf) { + imgW = resPixbuf->get_width(); + imgH = resPixbuf->get_height(); + imgX = (W-imgW)/2; + imgY = (H-imgH)/2; + backBuffer->draw_pixbuf (get_style()->get_base_gc(Gtk::STATE_NORMAL), resPixbuf, 0, 0, imgX, imgY, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0); + Cairo::RefPtr cr = backBuffer->create_cairo_context(); + if (previewHandler->getCropParams().enabled) + drawCrop (cr, imgX, imgY, imgW, imgH, 0, 0, zoom, previewHandler->getCropParams(), true, false); + } + } +} + +void PreviewWindow::setPreviewHandler (PreviewHandler* ph) { + + previewHandler = ph; + if (previewHandler) + previewHandler->addPreviewImageListener (this); +} + +void PreviewWindow::on_resized (Gtk::Allocation& req) { + + updatePreviewImage (); + queue_draw (); +} + +bool PreviewWindow::on_expose_event (GdkEventExpose* event) { + + if (backBuffer) { + Glib::RefPtr window = get_window(); + + int bufferW, bufferH; + backBuffer->get_size (bufferW, bufferH); + + if (!mainCropWin && imageArea) { + mainCropWin = imageArea->getMainCropWindow (); + if (mainCropWin) + mainCropWin->addCropWindowListener (this); + } + if ((get_width()!=bufferW && get_height()!=bufferH) || needsUpdate) { - needsUpdate = false; - updatePreviewImage (); - } - window->draw_drawable (get_style()->get_base_gc(Gtk::STATE_NORMAL), backBuffer, 0, 0, 0, 0, -1, -1); - + needsUpdate = false; + updatePreviewImage (); + } + window->draw_drawable (get_style()->get_base_gc(Gtk::STATE_NORMAL), backBuffer, 0, 0, 0, 0, -1, -1); + if (mainCropWin && zoom > 0.0) { - if(mainCropWin->getZoom() > mainCropWin->cropHandler.getFitZoom()) { - Cairo::RefPtr cr = get_window()->create_cairo_context(); - int x, y, w, h; - getObservedFrameArea (x, y, w, h); - double rectX = x + 0.5; - double rectY = y + 0.5; - double rectW = std::min(w, (int)(imgW - (x-imgX) - 1)); - double rectH = std::min(h, (int)(imgH - (y-imgY) - 1)); - - // draw a black "shadow" line - cr->set_source_rgba (0.0, 0.0, 0.0, 0.65); - cr->set_line_width (1); - cr->rectangle (rectX+1., rectY+1, rectW, rectH); - cr->stroke (); - - // draw a "frame" line. Color of frame line can be set in preferences - cr->set_source_rgba(options.navGuideBrush[0], options.navGuideBrush[1], options.navGuideBrush[2], options.navGuideBrush[3]); //( 1.0, 1.0, 1.0, 1.0); - cr->rectangle (rectX, rectY, rectW, rectH); - cr->stroke (); - } - } - } - return true; -} - -void PreviewWindow::previewImageChanged () { - - updatePreviewImage (); - queue_draw (); -} - -void PreviewWindow::setImageArea (ImageArea* ia) { - - imageArea = ia; - mainCropWin = ia->getMainCropWindow (); - if (mainCropWin) - mainCropWin->addCropWindowListener (this); -} - -void PreviewWindow::cropPositionChanged (CropWindow* w) { - - queue_draw (); -} - -void PreviewWindow::cropWindowSizeChanged (CropWindow* w) { - - queue_draw (); -} - -void PreviewWindow::cropZoomChanged (CropWindow* w) { - - queue_draw (); -} - -bool PreviewWindow::on_motion_notify_event (GdkEventMotion* event) { - - if (!mainCropWin) - return true; - - if(mainCropWin->getZoom() > mainCropWin->cropHandler.getFitZoom()) { - int x, y, w, h; - getObservedFrameArea (x, y, w, h); - bool inside = event->x > x-6 && event->x < x+w-1+6 && event->y > y-6 && event->y < y+h-1+6; - bool moreInside = event->x > x+6 && event->x < x+w-1-6 && event->y > y+6 && event->y < y+h-1-6; - - if (isMoving) - mainCropWin->remoteMove ((event->x - press_x)/zoom, (event->y - press_y)/zoom); - else if (inside && !moreInside) - cursorManager.setCursor (get_window(), CSClosedHand); - else - cursorManager.setCursor (get_window(), CSArrow); - } - return true; -} - -bool PreviewWindow::on_button_press_event (GdkEventButton* event) { - - if (!mainCropWin) - return true; - - if(mainCropWin->getZoom() > mainCropWin->cropHandler.getFitZoom()) { - int x, y, w, h; - getObservedFrameArea (x, y, w, h); - bool inside = event->x > x-6 && event->x < x+w-1+6 && event->y > y-6 && event->y < y+h-1+6; - bool moreInside = event->x > x+6 && event->x < x+w-1-6 && event->y > y+6 && event->y < y+h-1-6; - - if (!isMoving) { - isMoving = true; - if (!inside || moreInside) { - mainCropWin->remoteMove ((event->x - (x+w/2))/zoom, (event->y - (y+h/2))/zoom); - press_x = x+w/2; - press_y = y+h/2; - } - else { - press_x = event->x; - press_y = event->y; - } - cursorManager.setCursor (get_window(), CSClosedHand); - } - } - return true; -} - -bool PreviewWindow::on_button_release_event (GdkEventButton* event) { - - if (!mainCropWin) - return true; - - if (isMoving) { - isMoving = false; - cursorManager.setCursor (get_window(), CSArrow); - mainCropWin->remoteMoveReady (); - } - return true; -} + if(mainCropWin->getZoom() > mainCropWin->cropHandler.getFitZoom()) { + Cairo::RefPtr cr = get_window()->create_cairo_context(); + int x, y, w, h; + getObservedFrameArea (x, y, w, h); + double rectX = x + 0.5; + double rectY = y + 0.5; + double rectW = std::min(w, (int)(imgW - (x-imgX) - 1)); + double rectH = std::min(h, (int)(imgH - (y-imgY) - 1)); + + // draw a black "shadow" line + cr->set_source_rgba (0.0, 0.0, 0.0, 0.65); + cr->set_line_width (1); + cr->rectangle (rectX+1., rectY+1, rectW, rectH); + cr->stroke (); + + // draw a "frame" line. Color of frame line can be set in preferences + cr->set_source_rgba(options.navGuideBrush[0], options.navGuideBrush[1], options.navGuideBrush[2], options.navGuideBrush[3]); //( 1.0, 1.0, 1.0, 1.0); + cr->rectangle (rectX, rectY, rectW, rectH); + cr->stroke (); + } + } + } + return true; +} + +void PreviewWindow::previewImageChanged () { + + updatePreviewImage (); + queue_draw (); +} + +void PreviewWindow::setImageArea (ImageArea* ia) { + + imageArea = ia; + mainCropWin = ia->getMainCropWindow (); + if (mainCropWin) + mainCropWin->addCropWindowListener (this); +} + +void PreviewWindow::cropPositionChanged (CropWindow* w) { + + queue_draw (); +} + +void PreviewWindow::cropWindowSizeChanged (CropWindow* w) { + + queue_draw (); +} + +void PreviewWindow::cropZoomChanged (CropWindow* w) { + + queue_draw (); +} + +bool PreviewWindow::on_motion_notify_event (GdkEventMotion* event) { + + if (!mainCropWin) + return true; + + if(mainCropWin->getZoom() > mainCropWin->cropHandler.getFitZoom()) { + int x, y, w, h; + getObservedFrameArea (x, y, w, h); + bool inside = event->x > x-6 && event->x < x+w-1+6 && event->y > y-6 && event->y < y+h-1+6; + bool moreInside = event->x > x+6 && event->x < x+w-1-6 && event->y > y+6 && event->y < y+h-1-6; + + if (isMoving) + mainCropWin->remoteMove ((event->x - press_x)/zoom, (event->y - press_y)/zoom); + else if (inside && !moreInside) + cursorManager.setCursor (get_window(), CSClosedHand); + else + cursorManager.setCursor (get_window(), CSArrow); + } + return true; +} + +bool PreviewWindow::on_button_press_event (GdkEventButton* event) { + + if (!mainCropWin) + return true; + + if(mainCropWin->getZoom() > mainCropWin->cropHandler.getFitZoom()) { + int x, y, w, h; + getObservedFrameArea (x, y, w, h); + bool inside = event->x > x-6 && event->x < x+w-1+6 && event->y > y-6 && event->y < y+h-1+6; + bool moreInside = event->x > x+6 && event->x < x+w-1-6 && event->y > y+6 && event->y < y+h-1-6; + + if (!isMoving) { + isMoving = true; + if (!inside || moreInside) { + mainCropWin->remoteMove ((event->x - (x+w/2))/zoom, (event->y - (y+h/2))/zoom); + press_x = x+w/2; + press_y = y+h/2; + } + else { + press_x = event->x; + press_y = event->y; + } + cursorManager.setCursor (get_window(), CSClosedHand); + } + } + return true; +} + +bool PreviewWindow::on_button_release_event (GdkEventButton* event) { + + if (!mainCropWin) + return true; + + if (isMoving) { + isMoving = false; + cursorManager.setCursor (get_window(), CSArrow); + mainCropWin->remoteMoveReady (); + } + return true; +} diff --git a/rtgui/profilepanel.cc b/rtgui/profilepanel.cc index d043892be..cb7d1ae40 100644 --- a/rtgui/profilepanel.cc +++ b/rtgui/profilepanel.cc @@ -1,700 +1,700 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "profilepanel.h" -#include "options.h" -#include "profilestore.h" -#include "clipboard.h" -#include "multilangmgr.h" -#include "../rtengine/safegtk.h" -#include "rtimage.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -PartialPasteDlg* ProfilePanel::partialProfileDlg; - - -void ProfilePanel::init () { - partialProfileDlg = new PartialPasteDlg("Foo"); -} - -void ProfilePanel::cleanup () { - delete partialProfileDlg; -} - -ProfilePanel::ProfilePanel (bool readOnly) : storedPProfile(NULL), lastFilename(""), imagePath("") { - - tpc = NULL; - - profileFillModeOnImage = new RTImage("profile-filled.png"); - profileFillModeOffImage = new RTImage("profile-partial.png"); - fillMode = Gtk::manage (new Gtk::ToggleButton()); - fillMode->set_active(options.filledProfile); - fillMode->add( options.filledProfile ? *profileFillModeOnImage : *profileFillModeOffImage ); - fillMode->signal_toggled().connect ( sigc::mem_fun(*this, &ProfilePanel::profileFillModeToggled) ); - fillMode->set_tooltip_text(M("PROFILEPANEL_MODE_TIP")); - - // Create the Combobox - profiles = Gtk::manage (new ProfileStoreComboBox ()); - - Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox ()); - hbox->show (); -// pack_start (*profiles, Gtk::PACK_SHRINK, 4); - - pack_start (*hbox, Gtk::PACK_SHRINK, 4); - - load = Gtk::manage (new Gtk::Button ()); - load->add (*Gtk::manage (new RTImage ("gtk-open.png"))); - if (!readOnly) save = Gtk::manage (new Gtk::Button ()); - if (!readOnly) save->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); - if (!readOnly) copy = Gtk::manage (new Gtk::Button ()); - if (!readOnly) copy->add (*Gtk::manage (new RTImage ("edit-copy.png"))); - paste = Gtk::manage (new Gtk::Button ()); - paste->add (*Gtk::manage (new RTImage ("edit-paste.png"))); - - hbox->pack_start (*fillMode, Gtk::PACK_SHRINK, 1); - hbox->pack_start (*profiles); - hbox->pack_start (*load, Gtk::PACK_SHRINK, 1); - if (!readOnly) hbox->pack_start (*save, Gtk::PACK_SHRINK, 1); - hbox->pack_start (*copy, Gtk::PACK_SHRINK, 1); - if (!readOnly) hbox->pack_start (*paste, Gtk::PACK_SHRINK, 1); - - load->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &ProfilePanel::load_clicked) ); - if (!readOnly) save->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &ProfilePanel::save_clicked) ); - if (!readOnly) copy->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &ProfilePanel::copy_clicked) ); - paste->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &ProfilePanel::paste_clicked) ); - - custom = NULL; - lastsaved = NULL; - dontupdate = false; - - profileStore.addListener(this); - - changeconn = profiles->signal_changed().connect( sigc::mem_fun(*this, &ProfilePanel::selection_changed) ); - - load->set_tooltip_markup (M("PROFILEPANEL_TOOLTIPLOAD")); - if (!readOnly) save->set_tooltip_markup (M("PROFILEPANEL_TOOLTIPSAVE")); - if (!readOnly) copy->set_tooltip_markup (M("PROFILEPANEL_TOOLTIPCOPY")); - paste->set_tooltip_markup (M("PROFILEPANEL_TOOLTIPPASTE")); - - show_all_children (); -} - -ProfilePanel::~ProfilePanel () { - - profileStore.removeListener(this); - if (custom) { custom->deleteInstance(); delete custom; } - if (lastsaved) { lastsaved->deleteInstance(); delete lastsaved; } - delete profileFillModeOnImage; - delete profileFillModeOffImage; -} - -bool ProfilePanel::isCustomSelected() { - if (profiles->getCurrentLabel() == Glib::ustring ("(" + M("PROFILEPANEL_PCUSTOM") + ")")) - return true; - return false; -} - -bool ProfilePanel::isLastSavedSelected() { - if (profiles->getCurrentLabel() == Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")")) - return true; - return false; -} - -Gtk::TreeIter ProfilePanel::getCustomRow() { - Gtk::TreeIter row; - if (custom) - row = profiles->getRowFromLabel(Glib::ustring ("(" + M("PROFILEPANEL_PCUSTOM") + ")")); - return row; -} - -Gtk::TreeIter ProfilePanel::getLastSavedRow() { - Gtk::TreeIter row; - if (lastsaved) { - row = profiles->getRowFromLabel(Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")")); - } - return row; -} - -Gtk::TreeIter ProfilePanel::addCustomRow() { - const ProfileStoreEntry *customPSE = new ProfileStoreEntry(Glib::ustring ("(" + M("PROFILEPANEL_PCUSTOM") + ")"), PSET_FILE, 0, 0); - Gtk::TreeIter newEntry = profiles->addRow(customPSE); - return newEntry; -} - -Gtk::TreeIter ProfilePanel::addLastSavedRow() { - const ProfileStoreEntry *lastSavedPSE = new ProfileStoreEntry(Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")"), PSET_FILE, 0, 0); - Gtk::TreeIter newEntry = profiles->addRow(lastSavedPSE); - return newEntry; -} - -void ProfilePanel::storeCurrentValue () { - // TODO: Find a way to get and restore the current selection; the following line can't work anymore - storedValue = profiles->getFullPathFromActiveRow(); - if (!isCustomSelected() && !isLastSavedSelected()) { - // storing the current entry's procparams, if not "Custom" or "LastSaved" - - // for now, the storedPProfile has default internal values - const ProfileStoreEntry *entry = profiles->getSelectedEntry(); - const PartialProfile *currProfile; - if (entry && (currProfile = profileStore.getProfile(entry))!=NULL) { - // now storedPProfile has the current entry's values - storedPProfile = new PartialProfile(currProfile->pparams, currProfile->pedited, true); - } - else - storedPProfile = new PartialProfile(true); - } -} - -/* Get the ProfileStore's entry list and recreate the combobox entries - * If you want want to update the ProfileStore list itself (rescan the dir tree), use its "parseProfiles" method instead - */ -void ProfilePanel::updateProfileList () { - - bool ccPrevState = changeconn.block(true); - - // rescan file tree - profiles->updateProfileList(); - - if (custom) - addCustomRow(); - - if (lastsaved) - addLastSavedRow(); - - changeconn.block (ccPrevState); -} - -void ProfilePanel::restoreValue () { - bool ccPrevState = changeconn.block(true); - - if (!profiles->setActiveRowFromFullPath(storedValue) && storedPProfile) { - if (custom) delete custom; - custom = new PartialProfile (storedPProfile->pparams, storedPProfile->pedited, true); - Gtk::TreeIter custRow = getCustomRow(); - if (custRow) - profiles->set_active(custRow); - else - profiles->set_active (addCustomRow()); - } - - currRow = profiles->get_active(); - - changeconn.block (ccPrevState); - - storedValue = ""; - - if (storedPProfile) { - storedPProfile->deleteInstance(); - delete storedPProfile; - storedPProfile = NULL; - } -} - -void ProfilePanel::save_clicked (GdkEventButton* event) { - - if (event->button != 1) - return; - - Gtk::FileChooserDialog dialog(M("PROFILEPANEL_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE); - FileChooserLastFolderPersister persister( &dialog, options.loadSaveProfilePath ); - dialog.set_current_name (lastFilename); - - //Add the user's default (or global if multiuser=false) profile path to the Shortcut list -#ifdef WIN32 - // Dirty workaround, waiting for a clean solution by using exceptions! - if (!safe_is_shortcut_dir(options.getPreferredProfilePath())) -#endif - try { - dialog.add_shortcut_folder(options.getPreferredProfilePath()); - } - catch (Glib::Error &err) {} - //Add the image's path to the Shortcut list -#ifdef WIN32 - // Dirty workaround, waiting for a clean solution by using exceptions! - if (!safe_is_shortcut_dir(imagePath)) -#endif - try { - dialog.add_shortcut_folder(imagePath); - } - catch (Glib::Error &err) {} - - //Add response buttons the the dialog: - dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_OK); - - //Add filters, so that only certain file types can be selected: - - Gtk::FileFilter filter_pp; - filter_pp.set_name(M("FILECHOOSER_FILTER_PP")); - filter_pp.add_pattern("*"+paramFileExtension); - dialog.add_filter(filter_pp); - - Gtk::FileFilter filter_any; - filter_any.set_name(M("FILECHOOSER_FILTER_ANY")); - filter_any.add_pattern("*"); - dialog.add_filter(filter_any); - -// dialog.set_do_overwrite_confirmation (true); - - bool done = false; - do { - if (dialog.run()==Gtk::RESPONSE_OK) { - - std::string fname = dialog.get_filename(); - Glib::ustring ext = getExtension (fname); - - if (("." + ext) != paramFileExtension) - fname += paramFileExtension; - - if (!confirmOverwrite (dialog, fname)) - continue; - - lastFilename = Glib::path_get_basename (fname); - - const PartialProfile* toSave; - if (isCustomSelected()) - toSave = custom; - else if (isLastSavedSelected()) - toSave = lastsaved; - else { - const ProfileStoreEntry* entry = profiles->getSelectedEntry(); - toSave = entry ? profileStore.getProfile (profiles->getSelectedEntry()) : NULL; - } - - if (toSave) { - if (event->state & Gdk::CONTROL_MASK) { - // opening the partial paste dialog window - partialProfileDlg->set_title(M("PROFILEPANEL_SAVEPPASTE")); - int i = partialProfileDlg->run(); - partialProfileDlg->hide(); - if (i != Gtk::RESPONSE_OK) - return; - - // saving the partial profile - PartialProfile ppTemp(true); - partialProfileDlg->applyPaste (ppTemp.pparams, ppTemp.pedited, toSave->pparams, toSave->pedited); - int retCode = ppTemp.pparams->save (fname, "", true, ppTemp.pedited); - ppTemp.deleteInstance(); - if (retCode) - writeFailed(dialog, fname); - else { - done=true; - bool ccPrevState = changeconn.block(true); - profileStore.parseProfiles(); - changeconn.block (ccPrevState); - } - } - else { - // saving a full profile - int retCode = toSave->pparams->save (fname); - if (retCode) - writeFailed(dialog, fname); - else { - done=true; - bool ccPrevState = changeconn.block(true); - profileStore.parseProfiles(); - changeconn.block (ccPrevState); - } - } - } - else done = true; - } - else done = true; - } while (!done); - return; -} - -/* - * Copy the actual full profile to the clipboard - */ -void ProfilePanel::copy_clicked (GdkEventButton* event) { - - if (event->button != 1) - return; - - const PartialProfile* toSave; - if (isCustomSelected()) - toSave = custom; - else if (isLastSavedSelected()) - toSave = lastsaved; - else { - const ProfileStoreEntry* entry = profiles->getSelectedEntry(); - toSave = entry ? profileStore.getProfile (entry) : NULL; - } - - // toSave has to be a complete procparams - if (toSave) { - if (event->state & Gdk::CONTROL_MASK) { - // opening the partial paste dialog window - partialProfileDlg->set_title(M("PROFILEPANEL_COPYPPASTE")); - int i = partialProfileDlg->run(); - partialProfileDlg->hide(); - if (i != Gtk::RESPONSE_OK) - return; - - // saving a partial profile - PartialProfile ppTemp(true); - partialProfileDlg->applyPaste (ppTemp.pparams, ppTemp.pedited, toSave->pparams, toSave->pedited); - clipboard.setPartialProfile(ppTemp); - ppTemp.deleteInstance(); - } - else - clipboard.setProcParams (*toSave->pparams); - } - return; -} - -/* - * Load a potentially partial profile - */ -void ProfilePanel::load_clicked (GdkEventButton* event) { - - if (event->button != 1) - return; - - Gtk::FileChooserDialog dialog(M("PROFILEPANEL_LOADDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN); - FileChooserLastFolderPersister persister( &dialog, options.loadSaveProfilePath ); - - //Add the user's default (or global if multiuser=false) profile path to the Shortcut list -#ifdef WIN32 - // Dirty workaround, waiting for a clean solution by using exceptions! - if (!safe_is_shortcut_dir(options.getPreferredProfilePath())) -#endif - try { - dialog.add_shortcut_folder(options.getPreferredProfilePath()); - } - catch (Glib::Error &err) {} - - //Add the image's path to the Shortcut list -#ifdef WIN32 - // Dirty workaround, waiting for a clean solution by using exceptions! - if (!safe_is_shortcut_dir(imagePath)) -#endif - try { - dialog.add_shortcut_folder(imagePath); - } - catch (Glib::Error &err) {} - - //Add response buttons the the dialog: - dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::StockID("gtk-open"), Gtk::RESPONSE_OK); - - //Add filters, so that only certain file types can be selected: - - Gtk::FileFilter filter_pp; - filter_pp.set_name(M("FILECHOOSER_FILTER_PP")); - filter_pp.add_pattern("*"+paramFileExtension); - dialog.add_filter(filter_pp); - - Gtk::FileFilter filter_any; - filter_any.set_name(M("FILECHOOSER_FILTER_ANY")); - filter_any.add_pattern("*"); - dialog.add_filter(filter_any); - - int result = dialog.run(); - dialog.hide(); - - if (result==Gtk::RESPONSE_OK) { - Glib::ustring fname = dialog.get_filename(); - - if (event->state & Gdk::CONTROL_MASK) { - // opening the partial paste dialog window - partialProfileDlg->set_title(M("PROFILEPANEL_LOADPPASTE")); - int i = partialProfileDlg->run(); - partialProfileDlg->hide(); - if (i != Gtk::RESPONSE_OK) - return; - } - bool customCreated = false; - if (!custom) { - custom = new PartialProfile (true); - customCreated = true; - } - - ProcParams pp; - ParamsEdited pe; - int err = pp.load (fname, &pe); - if (!err) { - if (!customCreated && fillMode->get_active()) - custom->pparams->setDefaults(); - custom->set(true); - - bool prevState = changeconn.block(true); - Gtk::TreeIter newEntry = addCustomRow(); - profiles->set_active (newEntry); - currRow = profiles->get_active(); - changeconn.block(prevState); - - // Now we have procparams initialized to default if fillMode is on - // and paramsedited initialized to default in all cases - - if (event->state & Gdk::CONTROL_MASK) - // custom.pparams = loadedFile.pparams filtered by ( loadedFile.pedited & partialPaste.pedited ) - partialProfileDlg->applyPaste (custom->pparams, !fillMode->get_active()?custom->pedited:NULL, &pp, &pe); - else { - // custom.pparams = loadedFile.pparams filtered by ( loadedFile.pedited ) - pe.combine(*custom->pparams, pp, true); - if (!fillMode->get_active()) - *custom->pedited = pe; - } - - changeTo (custom, M("PROFILEPANEL_PFILE")); - } - else if (customCreated) { - // we delete custom - custom->deleteInstance(); - delete custom; custom = NULL; - } - } - return; -} - -/* - * Paste a full profile from the clipboard - */ -void ProfilePanel::paste_clicked (GdkEventButton* event) { - - if (event->button != 1) - return; - if (!clipboard.hasProcParams()) - return; - - if (event->state & Gdk::CONTROL_MASK) { - partialProfileDlg->set_title(M("PROFILEPANEL_PASTEPPASTE")); - int i = partialProfileDlg->run(); - partialProfileDlg->hide(); - if (i != Gtk::RESPONSE_OK) - return; - } - - bool prevState = changeconn.block(true); - - if (!custom) { - custom = new PartialProfile (true); - if (isLastSavedSelected()) { - *custom->pparams = *lastsaved->pparams; - } - else { - const ProfileStoreEntry* entry = profiles->getSelectedEntry(); - if (entry) { - const PartialProfile* partProfile = profileStore.getProfile (entry); - *custom->pparams = *partProfile->pparams; - } - } - profiles->set_active (addCustomRow()); - currRow = profiles->get_active(); - } - else { - if (fillMode->get_active()) - custom->pparams->setDefaults(); - profiles->set_active(getCustomRow()); - currRow = profiles->get_active(); - } - custom->pedited->set(true); - - changeconn.block(prevState); - - // Now we have procparams initialized to default if fillMode is on - // and paramsedited initialized to default in all cases - - ProcParams pp = clipboard.getProcParams (); - if (clipboard.hasPEdited()) { - ParamsEdited pe = clipboard.getParamsEdited(); - if (event->state & Gdk::CONTROL_MASK) - // custom.pparams = clipboard.pparams filtered by ( clipboard.pedited & partialPaste.pedited ) - partialProfileDlg->applyPaste (custom->pparams, !fillMode->get_active()?custom->pedited:NULL, &pp, &pe); - else { - // custom.pparams = clipboard.pparams filtered by ( clipboard.pedited ) - pe.combine(*custom->pparams, pp, true); - if (!fillMode->get_active()) - *custom->pedited = pe; - } - } - else { - if (event->state & Gdk::CONTROL_MASK) - // custom.pparams = clipboard.pparams filtered by ( partialPaste.pedited ) - partialProfileDlg->applyPaste (custom->pparams, NULL, &pp, NULL); - else { - // custom.pparams = clipboard.pparams non filtered - *custom->pparams = pp; - } - } - - changeTo (custom, M("HISTORY_FROMCLIPBOARD")); - return; -} - -void ProfilePanel::changeTo (const PartialProfile* newpp, Glib::ustring profname) { - - if (!newpp) - return; - - if (tpc) - tpc->profileChange (newpp, EvProfileChanged, profname); -} - -void ProfilePanel::selection_changed () { - - if (isCustomSelected()) { - if (!dontupdate) - changeTo (custom, Glib::ustring ("(" + M("PROFILEPANEL_PCUSTOM") + ")")); - } - else if (isLastSavedSelected()) - changeTo (lastsaved, Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")")); - else { - const ProfileStoreEntry *pse = profiles->getSelectedEntry(); - if (pse->type == PSET_FOLDER) { - // this entry is invalid, restoring the old value - bool ccPrevState = changeconn.block(true); - profiles->set_active(currRow); - changeconn.block(ccPrevState); - dontupdate = false; - return; - } - else - currRow = profiles->get_active(); - - const PartialProfile* s = profileStore.getProfile (pse); - if (s) { - if (fillMode->get_active() && s->pedited) { - ParamsEdited pe(true); - PartialProfile s2(s->pparams, &pe, false); - changeTo (&s2, pse->label+"+"); - } - else - changeTo (s, pse->label); - } - } - dontupdate = false; -} - -void ProfilePanel::procParamsChanged (rtengine::procparams::ProcParams* p, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) { - - // to prevent recursion, filter out the events caused by the profilepanel - if (ev==EvProfileChanged || ev==EvPhotoLoaded) - return; - - if (!isCustomSelected()) { - dontupdate = true; - if (!custom) { - custom = new PartialProfile (true); - custom->set(true); - profiles->set_active (addCustomRow()); - currRow = profiles->get_active(); - } - else { - profiles->set_active(getCustomRow()); - currRow = profiles->get_active(); - } - } - *custom->pparams = *p; -} - -/** @brief Initialize the Profile panel with a default profile, overridden by the last saved profile if provided - * - * The file tree has already been created on object's construction. We add here the Custom, LastSaved and/or Internal item. - * - * @param profileFullPath full path of the profile; must start by the virtual root (${G} or ${U}, and without suffix - * @param lastSaved pointer to the last saved ProcParam; may be NULL - */ -void ProfilePanel::initProfile (const Glib::ustring& profileFullPath, ProcParams* lastSaved) { - - const ProfileStoreEntry *pse = NULL; - const PartialProfile *defprofile = NULL; - - bool ccPrevState = changeconn.block(true); - - if (custom) { - custom->deleteInstance(); - delete custom; custom = NULL; - } - - if (lastsaved) { - lastsaved->deleteInstance(); - delete lastsaved; lastsaved = NULL; - } - if (lastSaved) { - ParamsEdited* pe = new ParamsEdited(true); - // copying the provided last saved profile to ProfilePanel::lastsaved - lastsaved = new PartialProfile(lastSaved, pe); - } - - // update the content of the combobox; will add 'custom' and 'lastSaved' if necessary - updateProfileList(); - - Gtk::TreeIter lasSavedEntry; - // adding the Last Saved combobox entry, if needed - if (lastsaved) { - defprofile = lastsaved; - lasSavedEntry = getLastSavedRow(); - } - - if (!(pse = profileStore.findEntryFromFullPath(profileFullPath))) { - // entry not found, pse = the Internal ProfileStoreEntry - pse = profileStore.getInternalDefaultPSE(); - } - - defprofile = profileStore.getProfile (pse); - - // selecting the "Internal" entry - profiles->setInternalEntry (); - currRow = profiles->get_active(); - - if (lastsaved) { - if (lasSavedEntry) profiles->set_active (lasSavedEntry); - currRow = profiles->get_active(); - if (tpc) { - tpc->setDefaults (lastsaved->pparams); - tpc->profileChange (lastsaved, EvPhotoLoaded, profiles->getSelectedEntry()->label); - } - } - else { - if (pse) { - profiles->setActiveRowFromEntry(pse); - currRow = profiles->get_active(); - } - if (tpc) { - tpc->setDefaults (defprofile->pparams); - tpc->profileChange (defprofile, EvPhotoLoaded, profiles->getSelectedEntry()->label); - } - } - changeconn.block (ccPrevState); -} - -void ProfilePanel::setInitialFileName (const Glib::ustring& filename) { - lastFilename = Glib::path_get_basename(filename) + paramFileExtension; - imagePath = Glib::path_get_dirname(filename); -} - -void ProfilePanel::profileFillModeToggled() { - if (fillMode->get_active()) { - // The button is pressed, we'll use the profileFillModeOnImage - fillMode->set_image(*profileFillModeOnImage); - } - else { - // The button is released, we'll use the profileFillModeOffImage - fillMode->set_image(*profileFillModeOffImage); - } -} - -void ProfilePanel::writeOptions() { - options.filledProfile = fillMode->get_active(); -} - +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "profilepanel.h" +#include "options.h" +#include "profilestore.h" +#include "clipboard.h" +#include "multilangmgr.h" +#include "../rtengine/safegtk.h" +#include "rtimage.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +PartialPasteDlg* ProfilePanel::partialProfileDlg; + + +void ProfilePanel::init () { + partialProfileDlg = new PartialPasteDlg("Foo"); +} + +void ProfilePanel::cleanup () { + delete partialProfileDlg; +} + +ProfilePanel::ProfilePanel (bool readOnly) : storedPProfile(NULL), lastFilename(""), imagePath("") { + + tpc = NULL; + + profileFillModeOnImage = new RTImage("profile-filled.png"); + profileFillModeOffImage = new RTImage("profile-partial.png"); + fillMode = Gtk::manage (new Gtk::ToggleButton()); + fillMode->set_active(options.filledProfile); + fillMode->add( options.filledProfile ? *profileFillModeOnImage : *profileFillModeOffImage ); + fillMode->signal_toggled().connect ( sigc::mem_fun(*this, &ProfilePanel::profileFillModeToggled) ); + fillMode->set_tooltip_text(M("PROFILEPANEL_MODE_TIP")); + + // Create the Combobox + profiles = Gtk::manage (new ProfileStoreComboBox ()); + + Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox ()); + hbox->show (); +// pack_start (*profiles, Gtk::PACK_SHRINK, 4); + + pack_start (*hbox, Gtk::PACK_SHRINK, 4); + + load = Gtk::manage (new Gtk::Button ()); + load->add (*Gtk::manage (new RTImage ("gtk-open.png"))); + if (!readOnly) save = Gtk::manage (new Gtk::Button ()); + if (!readOnly) save->add (*Gtk::manage (new RTImage ("gtk-save-large.png"))); + if (!readOnly) copy = Gtk::manage (new Gtk::Button ()); + if (!readOnly) copy->add (*Gtk::manage (new RTImage ("edit-copy.png"))); + paste = Gtk::manage (new Gtk::Button ()); + paste->add (*Gtk::manage (new RTImage ("edit-paste.png"))); + + hbox->pack_start (*fillMode, Gtk::PACK_SHRINK, 1); + hbox->pack_start (*profiles); + hbox->pack_start (*load, Gtk::PACK_SHRINK, 1); + if (!readOnly) hbox->pack_start (*save, Gtk::PACK_SHRINK, 1); + hbox->pack_start (*copy, Gtk::PACK_SHRINK, 1); + if (!readOnly) hbox->pack_start (*paste, Gtk::PACK_SHRINK, 1); + + load->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &ProfilePanel::load_clicked) ); + if (!readOnly) save->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &ProfilePanel::save_clicked) ); + if (!readOnly) copy->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &ProfilePanel::copy_clicked) ); + paste->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &ProfilePanel::paste_clicked) ); + + custom = NULL; + lastsaved = NULL; + dontupdate = false; + + profileStore.addListener(this); + + changeconn = profiles->signal_changed().connect( sigc::mem_fun(*this, &ProfilePanel::selection_changed) ); + + load->set_tooltip_markup (M("PROFILEPANEL_TOOLTIPLOAD")); + if (!readOnly) save->set_tooltip_markup (M("PROFILEPANEL_TOOLTIPSAVE")); + if (!readOnly) copy->set_tooltip_markup (M("PROFILEPANEL_TOOLTIPCOPY")); + paste->set_tooltip_markup (M("PROFILEPANEL_TOOLTIPPASTE")); + + show_all_children (); +} + +ProfilePanel::~ProfilePanel () { + + profileStore.removeListener(this); + if (custom) { custom->deleteInstance(); delete custom; } + if (lastsaved) { lastsaved->deleteInstance(); delete lastsaved; } + delete profileFillModeOnImage; + delete profileFillModeOffImage; +} + +bool ProfilePanel::isCustomSelected() { + if (profiles->getCurrentLabel() == Glib::ustring ("(" + M("PROFILEPANEL_PCUSTOM") + ")")) + return true; + return false; +} + +bool ProfilePanel::isLastSavedSelected() { + if (profiles->getCurrentLabel() == Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")")) + return true; + return false; +} + +Gtk::TreeIter ProfilePanel::getCustomRow() { + Gtk::TreeIter row; + if (custom) + row = profiles->getRowFromLabel(Glib::ustring ("(" + M("PROFILEPANEL_PCUSTOM") + ")")); + return row; +} + +Gtk::TreeIter ProfilePanel::getLastSavedRow() { + Gtk::TreeIter row; + if (lastsaved) { + row = profiles->getRowFromLabel(Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")")); + } + return row; +} + +Gtk::TreeIter ProfilePanel::addCustomRow() { + const ProfileStoreEntry *customPSE = new ProfileStoreEntry(Glib::ustring ("(" + M("PROFILEPANEL_PCUSTOM") + ")"), PSET_FILE, 0, 0); + Gtk::TreeIter newEntry = profiles->addRow(customPSE); + return newEntry; +} + +Gtk::TreeIter ProfilePanel::addLastSavedRow() { + const ProfileStoreEntry *lastSavedPSE = new ProfileStoreEntry(Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")"), PSET_FILE, 0, 0); + Gtk::TreeIter newEntry = profiles->addRow(lastSavedPSE); + return newEntry; +} + +void ProfilePanel::storeCurrentValue () { + // TODO: Find a way to get and restore the current selection; the following line can't work anymore + storedValue = profiles->getFullPathFromActiveRow(); + if (!isCustomSelected() && !isLastSavedSelected()) { + // storing the current entry's procparams, if not "Custom" or "LastSaved" + + // for now, the storedPProfile has default internal values + const ProfileStoreEntry *entry = profiles->getSelectedEntry(); + const PartialProfile *currProfile; + if (entry && (currProfile = profileStore.getProfile(entry))!=NULL) { + // now storedPProfile has the current entry's values + storedPProfile = new PartialProfile(currProfile->pparams, currProfile->pedited, true); + } + else + storedPProfile = new PartialProfile(true); + } +} + +/* Get the ProfileStore's entry list and recreate the combobox entries + * If you want want to update the ProfileStore list itself (rescan the dir tree), use its "parseProfiles" method instead + */ +void ProfilePanel::updateProfileList () { + + bool ccPrevState = changeconn.block(true); + + // rescan file tree + profiles->updateProfileList(); + + if (custom) + addCustomRow(); + + if (lastsaved) + addLastSavedRow(); + + changeconn.block (ccPrevState); +} + +void ProfilePanel::restoreValue () { + bool ccPrevState = changeconn.block(true); + + if (!profiles->setActiveRowFromFullPath(storedValue) && storedPProfile) { + if (custom) delete custom; + custom = new PartialProfile (storedPProfile->pparams, storedPProfile->pedited, true); + Gtk::TreeIter custRow = getCustomRow(); + if (custRow) + profiles->set_active(custRow); + else + profiles->set_active (addCustomRow()); + } + + currRow = profiles->get_active(); + + changeconn.block (ccPrevState); + + storedValue = ""; + + if (storedPProfile) { + storedPProfile->deleteInstance(); + delete storedPProfile; + storedPProfile = NULL; + } +} + +void ProfilePanel::save_clicked (GdkEventButton* event) { + + if (event->button != 1) + return; + + Gtk::FileChooserDialog dialog(M("PROFILEPANEL_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE); + FileChooserLastFolderPersister persister( &dialog, options.loadSaveProfilePath ); + dialog.set_current_name (lastFilename); + + //Add the user's default (or global if multiuser=false) profile path to the Shortcut list +#ifdef WIN32 + // Dirty workaround, waiting for a clean solution by using exceptions! + if (!safe_is_shortcut_dir(options.getPreferredProfilePath())) +#endif + try { + dialog.add_shortcut_folder(options.getPreferredProfilePath()); + } + catch (Glib::Error &err) {} + //Add the image's path to the Shortcut list +#ifdef WIN32 + // Dirty workaround, waiting for a clean solution by using exceptions! + if (!safe_is_shortcut_dir(imagePath)) +#endif + try { + dialog.add_shortcut_folder(imagePath); + } + catch (Glib::Error &err) {} + + //Add response buttons the the dialog: + dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_OK); + + //Add filters, so that only certain file types can be selected: + + Gtk::FileFilter filter_pp; + filter_pp.set_name(M("FILECHOOSER_FILTER_PP")); + filter_pp.add_pattern("*"+paramFileExtension); + dialog.add_filter(filter_pp); + + Gtk::FileFilter filter_any; + filter_any.set_name(M("FILECHOOSER_FILTER_ANY")); + filter_any.add_pattern("*"); + dialog.add_filter(filter_any); + +// dialog.set_do_overwrite_confirmation (true); + + bool done = false; + do { + if (dialog.run()==Gtk::RESPONSE_OK) { + + std::string fname = dialog.get_filename(); + Glib::ustring ext = getExtension (fname); + + if (("." + ext) != paramFileExtension) + fname += paramFileExtension; + + if (!confirmOverwrite (dialog, fname)) + continue; + + lastFilename = Glib::path_get_basename (fname); + + const PartialProfile* toSave; + if (isCustomSelected()) + toSave = custom; + else if (isLastSavedSelected()) + toSave = lastsaved; + else { + const ProfileStoreEntry* entry = profiles->getSelectedEntry(); + toSave = entry ? profileStore.getProfile (profiles->getSelectedEntry()) : NULL; + } + + if (toSave) { + if (event->state & Gdk::CONTROL_MASK) { + // opening the partial paste dialog window + partialProfileDlg->set_title(M("PROFILEPANEL_SAVEPPASTE")); + int i = partialProfileDlg->run(); + partialProfileDlg->hide(); + if (i != Gtk::RESPONSE_OK) + return; + + // saving the partial profile + PartialProfile ppTemp(true); + partialProfileDlg->applyPaste (ppTemp.pparams, ppTemp.pedited, toSave->pparams, toSave->pedited); + int retCode = ppTemp.pparams->save (fname, "", true, ppTemp.pedited); + ppTemp.deleteInstance(); + if (retCode) + writeFailed(dialog, fname); + else { + done=true; + bool ccPrevState = changeconn.block(true); + profileStore.parseProfiles(); + changeconn.block (ccPrevState); + } + } + else { + // saving a full profile + int retCode = toSave->pparams->save (fname); + if (retCode) + writeFailed(dialog, fname); + else { + done=true; + bool ccPrevState = changeconn.block(true); + profileStore.parseProfiles(); + changeconn.block (ccPrevState); + } + } + } + else done = true; + } + else done = true; + } while (!done); + return; +} + +/* + * Copy the actual full profile to the clipboard + */ +void ProfilePanel::copy_clicked (GdkEventButton* event) { + + if (event->button != 1) + return; + + const PartialProfile* toSave; + if (isCustomSelected()) + toSave = custom; + else if (isLastSavedSelected()) + toSave = lastsaved; + else { + const ProfileStoreEntry* entry = profiles->getSelectedEntry(); + toSave = entry ? profileStore.getProfile (entry) : NULL; + } + + // toSave has to be a complete procparams + if (toSave) { + if (event->state & Gdk::CONTROL_MASK) { + // opening the partial paste dialog window + partialProfileDlg->set_title(M("PROFILEPANEL_COPYPPASTE")); + int i = partialProfileDlg->run(); + partialProfileDlg->hide(); + if (i != Gtk::RESPONSE_OK) + return; + + // saving a partial profile + PartialProfile ppTemp(true); + partialProfileDlg->applyPaste (ppTemp.pparams, ppTemp.pedited, toSave->pparams, toSave->pedited); + clipboard.setPartialProfile(ppTemp); + ppTemp.deleteInstance(); + } + else + clipboard.setProcParams (*toSave->pparams); + } + return; +} + +/* + * Load a potentially partial profile + */ +void ProfilePanel::load_clicked (GdkEventButton* event) { + + if (event->button != 1) + return; + + Gtk::FileChooserDialog dialog(M("PROFILEPANEL_LOADDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN); + FileChooserLastFolderPersister persister( &dialog, options.loadSaveProfilePath ); + + //Add the user's default (or global if multiuser=false) profile path to the Shortcut list +#ifdef WIN32 + // Dirty workaround, waiting for a clean solution by using exceptions! + if (!safe_is_shortcut_dir(options.getPreferredProfilePath())) +#endif + try { + dialog.add_shortcut_folder(options.getPreferredProfilePath()); + } + catch (Glib::Error &err) {} + + //Add the image's path to the Shortcut list +#ifdef WIN32 + // Dirty workaround, waiting for a clean solution by using exceptions! + if (!safe_is_shortcut_dir(imagePath)) +#endif + try { + dialog.add_shortcut_folder(imagePath); + } + catch (Glib::Error &err) {} + + //Add response buttons the the dialog: + dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::StockID("gtk-open"), Gtk::RESPONSE_OK); + + //Add filters, so that only certain file types can be selected: + + Gtk::FileFilter filter_pp; + filter_pp.set_name(M("FILECHOOSER_FILTER_PP")); + filter_pp.add_pattern("*"+paramFileExtension); + dialog.add_filter(filter_pp); + + Gtk::FileFilter filter_any; + filter_any.set_name(M("FILECHOOSER_FILTER_ANY")); + filter_any.add_pattern("*"); + dialog.add_filter(filter_any); + + int result = dialog.run(); + dialog.hide(); + + if (result==Gtk::RESPONSE_OK) { + Glib::ustring fname = dialog.get_filename(); + + if (event->state & Gdk::CONTROL_MASK) { + // opening the partial paste dialog window + partialProfileDlg->set_title(M("PROFILEPANEL_LOADPPASTE")); + int i = partialProfileDlg->run(); + partialProfileDlg->hide(); + if (i != Gtk::RESPONSE_OK) + return; + } + bool customCreated = false; + if (!custom) { + custom = new PartialProfile (true); + customCreated = true; + } + + ProcParams pp; + ParamsEdited pe; + int err = pp.load (fname, &pe); + if (!err) { + if (!customCreated && fillMode->get_active()) + custom->pparams->setDefaults(); + custom->set(true); + + bool prevState = changeconn.block(true); + Gtk::TreeIter newEntry = addCustomRow(); + profiles->set_active (newEntry); + currRow = profiles->get_active(); + changeconn.block(prevState); + + // Now we have procparams initialized to default if fillMode is on + // and paramsedited initialized to default in all cases + + if (event->state & Gdk::CONTROL_MASK) + // custom.pparams = loadedFile.pparams filtered by ( loadedFile.pedited & partialPaste.pedited ) + partialProfileDlg->applyPaste (custom->pparams, !fillMode->get_active()?custom->pedited:NULL, &pp, &pe); + else { + // custom.pparams = loadedFile.pparams filtered by ( loadedFile.pedited ) + pe.combine(*custom->pparams, pp, true); + if (!fillMode->get_active()) + *custom->pedited = pe; + } + + changeTo (custom, M("PROFILEPANEL_PFILE")); + } + else if (customCreated) { + // we delete custom + custom->deleteInstance(); + delete custom; custom = NULL; + } + } + return; +} + +/* + * Paste a full profile from the clipboard + */ +void ProfilePanel::paste_clicked (GdkEventButton* event) { + + if (event->button != 1) + return; + if (!clipboard.hasProcParams()) + return; + + if (event->state & Gdk::CONTROL_MASK) { + partialProfileDlg->set_title(M("PROFILEPANEL_PASTEPPASTE")); + int i = partialProfileDlg->run(); + partialProfileDlg->hide(); + if (i != Gtk::RESPONSE_OK) + return; + } + + bool prevState = changeconn.block(true); + + if (!custom) { + custom = new PartialProfile (true); + if (isLastSavedSelected()) { + *custom->pparams = *lastsaved->pparams; + } + else { + const ProfileStoreEntry* entry = profiles->getSelectedEntry(); + if (entry) { + const PartialProfile* partProfile = profileStore.getProfile (entry); + *custom->pparams = *partProfile->pparams; + } + } + profiles->set_active (addCustomRow()); + currRow = profiles->get_active(); + } + else { + if (fillMode->get_active()) + custom->pparams->setDefaults(); + profiles->set_active(getCustomRow()); + currRow = profiles->get_active(); + } + custom->pedited->set(true); + + changeconn.block(prevState); + + // Now we have procparams initialized to default if fillMode is on + // and paramsedited initialized to default in all cases + + ProcParams pp = clipboard.getProcParams (); + if (clipboard.hasPEdited()) { + ParamsEdited pe = clipboard.getParamsEdited(); + if (event->state & Gdk::CONTROL_MASK) + // custom.pparams = clipboard.pparams filtered by ( clipboard.pedited & partialPaste.pedited ) + partialProfileDlg->applyPaste (custom->pparams, !fillMode->get_active()?custom->pedited:NULL, &pp, &pe); + else { + // custom.pparams = clipboard.pparams filtered by ( clipboard.pedited ) + pe.combine(*custom->pparams, pp, true); + if (!fillMode->get_active()) + *custom->pedited = pe; + } + } + else { + if (event->state & Gdk::CONTROL_MASK) + // custom.pparams = clipboard.pparams filtered by ( partialPaste.pedited ) + partialProfileDlg->applyPaste (custom->pparams, NULL, &pp, NULL); + else { + // custom.pparams = clipboard.pparams non filtered + *custom->pparams = pp; + } + } + + changeTo (custom, M("HISTORY_FROMCLIPBOARD")); + return; +} + +void ProfilePanel::changeTo (const PartialProfile* newpp, Glib::ustring profname) { + + if (!newpp) + return; + + if (tpc) + tpc->profileChange (newpp, EvProfileChanged, profname); +} + +void ProfilePanel::selection_changed () { + + if (isCustomSelected()) { + if (!dontupdate) + changeTo (custom, Glib::ustring ("(" + M("PROFILEPANEL_PCUSTOM") + ")")); + } + else if (isLastSavedSelected()) + changeTo (lastsaved, Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")")); + else { + const ProfileStoreEntry *pse = profiles->getSelectedEntry(); + if (pse->type == PSET_FOLDER) { + // this entry is invalid, restoring the old value + bool ccPrevState = changeconn.block(true); + profiles->set_active(currRow); + changeconn.block(ccPrevState); + dontupdate = false; + return; + } + else + currRow = profiles->get_active(); + + const PartialProfile* s = profileStore.getProfile (pse); + if (s) { + if (fillMode->get_active() && s->pedited) { + ParamsEdited pe(true); + PartialProfile s2(s->pparams, &pe, false); + changeTo (&s2, pse->label+"+"); + } + else + changeTo (s, pse->label); + } + } + dontupdate = false; +} + +void ProfilePanel::procParamsChanged (rtengine::procparams::ProcParams* p, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) { + + // to prevent recursion, filter out the events caused by the profilepanel + if (ev==EvProfileChanged || ev==EvPhotoLoaded) + return; + + if (!isCustomSelected()) { + dontupdate = true; + if (!custom) { + custom = new PartialProfile (true); + custom->set(true); + profiles->set_active (addCustomRow()); + currRow = profiles->get_active(); + } + else { + profiles->set_active(getCustomRow()); + currRow = profiles->get_active(); + } + } + *custom->pparams = *p; +} + +/** @brief Initialize the Profile panel with a default profile, overridden by the last saved profile if provided + * + * The file tree has already been created on object's construction. We add here the Custom, LastSaved and/or Internal item. + * + * @param profileFullPath full path of the profile; must start by the virtual root (${G} or ${U}, and without suffix + * @param lastSaved pointer to the last saved ProcParam; may be NULL + */ +void ProfilePanel::initProfile (const Glib::ustring& profileFullPath, ProcParams* lastSaved) { + + const ProfileStoreEntry *pse = NULL; + const PartialProfile *defprofile = NULL; + + bool ccPrevState = changeconn.block(true); + + if (custom) { + custom->deleteInstance(); + delete custom; custom = NULL; + } + + if (lastsaved) { + lastsaved->deleteInstance(); + delete lastsaved; lastsaved = NULL; + } + if (lastSaved) { + ParamsEdited* pe = new ParamsEdited(true); + // copying the provided last saved profile to ProfilePanel::lastsaved + lastsaved = new PartialProfile(lastSaved, pe); + } + + // update the content of the combobox; will add 'custom' and 'lastSaved' if necessary + updateProfileList(); + + Gtk::TreeIter lasSavedEntry; + // adding the Last Saved combobox entry, if needed + if (lastsaved) { + defprofile = lastsaved; + lasSavedEntry = getLastSavedRow(); + } + + if (!(pse = profileStore.findEntryFromFullPath(profileFullPath))) { + // entry not found, pse = the Internal ProfileStoreEntry + pse = profileStore.getInternalDefaultPSE(); + } + + defprofile = profileStore.getProfile (pse); + + // selecting the "Internal" entry + profiles->setInternalEntry (); + currRow = profiles->get_active(); + + if (lastsaved) { + if (lasSavedEntry) profiles->set_active (lasSavedEntry); + currRow = profiles->get_active(); + if (tpc) { + tpc->setDefaults (lastsaved->pparams); + tpc->profileChange (lastsaved, EvPhotoLoaded, profiles->getSelectedEntry()->label); + } + } + else { + if (pse) { + profiles->setActiveRowFromEntry(pse); + currRow = profiles->get_active(); + } + if (tpc) { + tpc->setDefaults (defprofile->pparams); + tpc->profileChange (defprofile, EvPhotoLoaded, profiles->getSelectedEntry()->label); + } + } + changeconn.block (ccPrevState); +} + +void ProfilePanel::setInitialFileName (const Glib::ustring& filename) { + lastFilename = Glib::path_get_basename(filename) + paramFileExtension; + imagePath = Glib::path_get_dirname(filename); +} + +void ProfilePanel::profileFillModeToggled() { + if (fillMode->get_active()) { + // The button is pressed, we'll use the profileFillModeOnImage + fillMode->set_image(*profileFillModeOnImage); + } + else { + // The button is released, we'll use the profileFillModeOffImage + fillMode->set_image(*profileFillModeOffImage); + } +} + +void ProfilePanel::writeOptions() { + options.filledProfile = fillMode->get_active(); +} + diff --git a/rtgui/rawcacorrection.cc b/rtgui/rawcacorrection.cc index b54e92449..60e4121a6 100644 --- a/rtgui/rawcacorrection.cc +++ b/rtgui/rawcacorrection.cc @@ -1,177 +1,177 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "rawcacorrection.h" -#include "guiutils.h" -#include "../rtengine/safegtk.h" -#include -#include "rtimage.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -RAWCACorr::RAWCACorr () : FoldableToolPanel(this, "rawcacorrection", M("TP_CHROMATABERR_LABEL")) -{ - Gtk::Image* icaredL = Gtk::manage (new RTImage ("ajd-ca-red1.png")); - Gtk::Image* icaredR = Gtk::manage (new RTImage ("ajd-ca-red2.png")); - Gtk::Image* icablueL = Gtk::manage (new RTImage ("ajd-ca-blue1.png")); - Gtk::Image* icablueR = Gtk::manage (new RTImage ("ajd-ca-blue2.png")); - - caAutocorrect = Gtk::manage(new Gtk::CheckButton((M("TP_RAWCACORR_AUTO")))); - caRed = Gtk::manage(new Adjuster (M("TP_RAWCACORR_CARED"),-4.0,4.0,0.1,0,icaredL,icaredR)); - caRed->setAdjusterListener (this); - if (caRed->delay < 1000) caRed->delay = 1000; - caRed->show(); - caBlue = Gtk::manage(new Adjuster (M("TP_RAWCACORR_CABLUE"),-4.0,4.0,0.1,0,icablueL,icablueR)); - caBlue->setAdjusterListener (this); - if (caBlue->delay < 1000) caBlue->delay = 1000; - caBlue->show(); - - pack_start( *caAutocorrect, Gtk::PACK_SHRINK, 4); - pack_start( *caRed, Gtk::PACK_SHRINK, 4); - pack_start( *caBlue, Gtk::PACK_SHRINK, 4); - - caacsconn = caAutocorrect->signal_toggled().connect ( sigc::mem_fun(*this, &RAWCACorr::caCorrectionChanged), true); -} - -void RAWCACorr::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - caacsconn.block (true); - - if(pedited ){ - caAutocorrect->set_inconsistent(!pedited->raw.caCorrection); - caRed->setEditedState( pedited->raw.caRed ? Edited : UnEdited ); - caBlue->setEditedState( pedited->raw.caBlue ? Edited : UnEdited ); - } - - lastCA = pp->raw.ca_autocorrect; - - // disable Red and Blue sliders when caAutocorrect is enabled - caRed->set_sensitive(!pp->raw.ca_autocorrect); - caBlue->set_sensitive(!pp->raw.ca_autocorrect); - - caAutocorrect->set_active(pp->raw.ca_autocorrect); - caRed->setValue (pp->raw.cared); - caBlue->setValue (pp->raw.cablue); - - caacsconn.block (false); - enableListener (); -} - -void RAWCACorr::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.ca_autocorrect = caAutocorrect->get_active(); - pp->raw.cared = caRed->getValue(); - pp->raw.cablue = caBlue->getValue(); - - if (pedited) { - pedited->raw.caCorrection = !caAutocorrect->get_inconsistent(); - pedited->raw.caRed = caRed->getEditedState (); - pedited->raw.caBlue = caBlue->getEditedState (); - } - -} - -void RAWCACorr::adjusterChanged (Adjuster* a, double newval) -{ - if (listener) { - - Glib::ustring value = a->getTextValue(); - - if (a == caRed) - listener->panelChanged (EvPreProcessCARed, value ); - else if (a == caBlue) - listener->panelChanged (EvPreProcessCABlue, value ); - } -} - -void RAWCACorr::setBatchMode(bool batchMode) -{ - ToolPanel::setBatchMode (batchMode); - caRed->showEditedCB (); - caBlue->showEditedCB (); -} - -void RAWCACorr::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) -{ - caRed->setDefault( defParams->raw.cared); - caBlue->setDefault( defParams->raw.cablue); - - if (pedited) { - caRed->setDefaultEditedState( pedited->raw.caRed ? Edited : UnEdited); - caBlue->setDefaultEditedState( pedited->raw.caBlue ? Edited : UnEdited); - } else { - caRed->setDefaultEditedState( Irrelevant ); - caBlue->setDefaultEditedState( Irrelevant ); - } -} - -void RAWCACorr::caCorrectionChanged() -{ - if (batchMode) { - if (caAutocorrect->get_inconsistent()) { - caAutocorrect->set_inconsistent (false); - caacsconn.block (true); - caAutocorrect->set_active (false); - caacsconn.block (false); - } - else if (lastCA) - caAutocorrect->set_inconsistent (true); - - lastCA = caAutocorrect->get_active (); - - } - /*else { - // For non batch mode, we disable the red and blue slider if caAutocorrect is true - if (caAutocorrect->get_active ()) { - caRed->set_sensitive(false); - caBlue->set_sensitive(false); - } - else { - caRed->set_sensitive(true); - caBlue->set_sensitive(true); - } - }*/ - - // disable Red and Blue sliders when caAutocorrect is enabled - caRed->set_sensitive(!caAutocorrect->get_active ()); - caBlue->set_sensitive(!caAutocorrect->get_active ()); - if (caAutocorrect->get_active ()){ - // set caRed and caBlue to 0 as RawImageSource::CA_correct_RT uses this as - // a condition for auto-CA correction. Alternative would be to change - // RawImageSource::CA_correct_RT and pass it ca_autocorrect value - caRed->setValue(0); - caBlue->setValue(0); - } - - if (listener) - listener->panelChanged (EvPreProcessAutoCA, caAutocorrect->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); -} - -void RAWCACorr::setAdjusterBehavior (bool caadd) { - - caRed->setAddMode(caadd); - caBlue->setAddMode(caadd); -} - -void RAWCACorr::trimValues (rtengine::procparams::ProcParams* pp) { - - caRed->trimValue(pp->raw.cared); - caBlue->trimValue(pp->raw.cablue); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "rawcacorrection.h" +#include "guiutils.h" +#include "../rtengine/safegtk.h" +#include +#include "rtimage.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +RAWCACorr::RAWCACorr () : FoldableToolPanel(this, "rawcacorrection", M("TP_CHROMATABERR_LABEL")) +{ + Gtk::Image* icaredL = Gtk::manage (new RTImage ("ajd-ca-red1.png")); + Gtk::Image* icaredR = Gtk::manage (new RTImage ("ajd-ca-red2.png")); + Gtk::Image* icablueL = Gtk::manage (new RTImage ("ajd-ca-blue1.png")); + Gtk::Image* icablueR = Gtk::manage (new RTImage ("ajd-ca-blue2.png")); + + caAutocorrect = Gtk::manage(new Gtk::CheckButton((M("TP_RAWCACORR_AUTO")))); + caRed = Gtk::manage(new Adjuster (M("TP_RAWCACORR_CARED"),-4.0,4.0,0.1,0,icaredL,icaredR)); + caRed->setAdjusterListener (this); + if (caRed->delay < 1000) caRed->delay = 1000; + caRed->show(); + caBlue = Gtk::manage(new Adjuster (M("TP_RAWCACORR_CABLUE"),-4.0,4.0,0.1,0,icablueL,icablueR)); + caBlue->setAdjusterListener (this); + if (caBlue->delay < 1000) caBlue->delay = 1000; + caBlue->show(); + + pack_start( *caAutocorrect, Gtk::PACK_SHRINK, 4); + pack_start( *caRed, Gtk::PACK_SHRINK, 4); + pack_start( *caBlue, Gtk::PACK_SHRINK, 4); + + caacsconn = caAutocorrect->signal_toggled().connect ( sigc::mem_fun(*this, &RAWCACorr::caCorrectionChanged), true); +} + +void RAWCACorr::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + caacsconn.block (true); + + if(pedited ){ + caAutocorrect->set_inconsistent(!pedited->raw.caCorrection); + caRed->setEditedState( pedited->raw.caRed ? Edited : UnEdited ); + caBlue->setEditedState( pedited->raw.caBlue ? Edited : UnEdited ); + } + + lastCA = pp->raw.ca_autocorrect; + + // disable Red and Blue sliders when caAutocorrect is enabled + caRed->set_sensitive(!pp->raw.ca_autocorrect); + caBlue->set_sensitive(!pp->raw.ca_autocorrect); + + caAutocorrect->set_active(pp->raw.ca_autocorrect); + caRed->setValue (pp->raw.cared); + caBlue->setValue (pp->raw.cablue); + + caacsconn.block (false); + enableListener (); +} + +void RAWCACorr::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.ca_autocorrect = caAutocorrect->get_active(); + pp->raw.cared = caRed->getValue(); + pp->raw.cablue = caBlue->getValue(); + + if (pedited) { + pedited->raw.caCorrection = !caAutocorrect->get_inconsistent(); + pedited->raw.caRed = caRed->getEditedState (); + pedited->raw.caBlue = caBlue->getEditedState (); + } + +} + +void RAWCACorr::adjusterChanged (Adjuster* a, double newval) +{ + if (listener) { + + Glib::ustring value = a->getTextValue(); + + if (a == caRed) + listener->panelChanged (EvPreProcessCARed, value ); + else if (a == caBlue) + listener->panelChanged (EvPreProcessCABlue, value ); + } +} + +void RAWCACorr::setBatchMode(bool batchMode) +{ + ToolPanel::setBatchMode (batchMode); + caRed->showEditedCB (); + caBlue->showEditedCB (); +} + +void RAWCACorr::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + caRed->setDefault( defParams->raw.cared); + caBlue->setDefault( defParams->raw.cablue); + + if (pedited) { + caRed->setDefaultEditedState( pedited->raw.caRed ? Edited : UnEdited); + caBlue->setDefaultEditedState( pedited->raw.caBlue ? Edited : UnEdited); + } else { + caRed->setDefaultEditedState( Irrelevant ); + caBlue->setDefaultEditedState( Irrelevant ); + } +} + +void RAWCACorr::caCorrectionChanged() +{ + if (batchMode) { + if (caAutocorrect->get_inconsistent()) { + caAutocorrect->set_inconsistent (false); + caacsconn.block (true); + caAutocorrect->set_active (false); + caacsconn.block (false); + } + else if (lastCA) + caAutocorrect->set_inconsistent (true); + + lastCA = caAutocorrect->get_active (); + + } + /*else { + // For non batch mode, we disable the red and blue slider if caAutocorrect is true + if (caAutocorrect->get_active ()) { + caRed->set_sensitive(false); + caBlue->set_sensitive(false); + } + else { + caRed->set_sensitive(true); + caBlue->set_sensitive(true); + } + }*/ + + // disable Red and Blue sliders when caAutocorrect is enabled + caRed->set_sensitive(!caAutocorrect->get_active ()); + caBlue->set_sensitive(!caAutocorrect->get_active ()); + if (caAutocorrect->get_active ()){ + // set caRed and caBlue to 0 as RawImageSource::CA_correct_RT uses this as + // a condition for auto-CA correction. Alternative would be to change + // RawImageSource::CA_correct_RT and pass it ca_autocorrect value + caRed->setValue(0); + caBlue->setValue(0); + } + + if (listener) + listener->panelChanged (EvPreProcessAutoCA, caAutocorrect->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); +} + +void RAWCACorr::setAdjusterBehavior (bool caadd) { + + caRed->setAddMode(caadd); + caBlue->setAddMode(caadd); +} + +void RAWCACorr::trimValues (rtengine::procparams::ProcParams* pp) { + + caRed->trimValue(pp->raw.cared); + caBlue->trimValue(pp->raw.cablue); +} diff --git a/rtgui/rawcacorrection.h b/rtgui/rawcacorrection.h index aa4d854dc..6d300c89d 100644 --- a/rtgui/rawcacorrection.h +++ b/rtgui/rawcacorrection.h @@ -1,51 +1,51 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _RAWCACORRECTION_H_ -#define _RAWCACORRECTION_H_ - -#include -#include "adjuster.h" -#include "toolpanel.h" -#include "../rtengine/rawimage.h" - -class RAWCACorr : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { - -protected: - Gtk::CheckButton* caAutocorrect; - Adjuster* caRed; - Adjuster* caBlue; - bool lastCA; - sigc::connection caacsconn; - -public: - - RAWCACorr (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - void setAdjusterBehavior (bool caadd); - void trimValues (rtengine::procparams::ProcParams* pp); - - void adjusterChanged (Adjuster* a, double newval); - void caCorrectionChanged (); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _RAWCACORRECTION_H_ +#define _RAWCACORRECTION_H_ + +#include +#include "adjuster.h" +#include "toolpanel.h" +#include "../rtengine/rawimage.h" + +class RAWCACorr : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { + +protected: + Gtk::CheckButton* caAutocorrect; + Adjuster* caRed; + Adjuster* caBlue; + bool lastCA; + sigc::connection caacsconn; + +public: + + RAWCACorr (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setAdjusterBehavior (bool caadd); + void trimValues (rtengine::procparams::ProcParams* pp); + + void adjusterChanged (Adjuster* a, double newval); + void caCorrectionChanged (); +}; + +#endif diff --git a/rtgui/rawexposure.cc b/rtgui/rawexposure.cc index 46d83fe60..0c91bfd77 100644 --- a/rtgui/rawexposure.cc +++ b/rtgui/rawexposure.cc @@ -1,113 +1,113 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "rawexposure.h" -#include "guiutils.h" -#include "../rtengine/safegtk.h" -#include - -using namespace rtengine; -using namespace rtengine::procparams; - -RAWExposure::RAWExposure () : FoldableToolPanel(this, "rawexposure", M("TP_EXPOS_WHITEPOINT_LABEL")) -{ - PexPos = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_LINEAR"),0.1,16.0,0.01,1)); - PexPos->setAdjusterListener (this); - if (PexPos->delay < 1000) PexPos->delay = 1000; - PexPos->show(); - PexPreser = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_PRESER"),0,2.5,0.1,0)); - PexPreser->setAdjusterListener (this); - if (PexPreser->delay < 1000) PexPreser->delay = 1000; - PexPreser->show(); - - pack_start( *PexPos, Gtk::PACK_SHRINK, 4);//exposi - // raw highlight exposure setting is obsolete, removing from GUI - //pack_start( *PexPreser, Gtk::PACK_SHRINK, 4); -} - -void RAWExposure::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - - if(pedited ){ - PexPos->setEditedState( pedited->raw.exPos ? Edited : UnEdited ); - PexPreser->setEditedState( pedited->raw.exPreser ? Edited : UnEdited ); - } - - PexPos->setValue (pp->raw.expos); - PexPreser->setValue (pp->raw.preser);//exposi - - enableListener (); -} - -void RAWExposure::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.expos = PexPos->getValue(); - pp->raw.preser = PexPreser->getValue();//exposi - - if (pedited) { - pedited->raw.exPos = PexPos->getEditedState (); - pedited->raw.exPreser = PexPreser->getEditedState ();//exposi - } - -} - -void RAWExposure::adjusterChanged (Adjuster* a, double newval) -{ - if (listener) { - Glib::ustring value = a->getTextValue(); - - if (a == PexPos ) - listener->panelChanged (EvPreProcessExpCorrLinear, value ); - else if (a == PexPreser && ABS(PexPos->getValue()-1.0)>0.0001) // update takes long, only do it if it would have an effect - listener->panelChanged (EvPreProcessExpCorrPH, value ); - } -} - -void RAWExposure::setBatchMode(bool batchMode) -{ - ToolPanel::setBatchMode (batchMode); - PexPos->showEditedCB (); - PexPreser->showEditedCB ();//exposure -} - -void RAWExposure::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) -{ - PexPos->setDefault( defParams->raw.expos); - PexPreser->setDefault( defParams->raw.preser); - - if (pedited) { - PexPos->setDefaultEditedState( pedited->raw.exPos ? Edited : UnEdited); - PexPreser->setDefaultEditedState( pedited->raw.exPreser ? Edited : UnEdited); - } else { - PexPos->setDefaultEditedState( Irrelevant ); - PexPreser->setDefaultEditedState( Irrelevant ); - } -} - -void RAWExposure::setAdjusterBehavior (bool pexposadd, bool pexpreseradd) { - - PexPos->setAddMode(pexposadd); - PexPreser->setAddMode(pexpreseradd); -} - -void RAWExposure::trimValues (rtengine::procparams::ProcParams* pp) { - - PexPos->trimValue(pp->raw.expos); - PexPreser->trimValue(pp->raw.preser); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "rawexposure.h" +#include "guiutils.h" +#include "../rtengine/safegtk.h" +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +RAWExposure::RAWExposure () : FoldableToolPanel(this, "rawexposure", M("TP_EXPOS_WHITEPOINT_LABEL")) +{ + PexPos = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_LINEAR"),0.1,16.0,0.01,1)); + PexPos->setAdjusterListener (this); + if (PexPos->delay < 1000) PexPos->delay = 1000; + PexPos->show(); + PexPreser = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_PRESER"),0,2.5,0.1,0)); + PexPreser->setAdjusterListener (this); + if (PexPreser->delay < 1000) PexPreser->delay = 1000; + PexPreser->show(); + + pack_start( *PexPos, Gtk::PACK_SHRINK, 4);//exposi + // raw highlight exposure setting is obsolete, removing from GUI + //pack_start( *PexPreser, Gtk::PACK_SHRINK, 4); +} + +void RAWExposure::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + + if(pedited ){ + PexPos->setEditedState( pedited->raw.exPos ? Edited : UnEdited ); + PexPreser->setEditedState( pedited->raw.exPreser ? Edited : UnEdited ); + } + + PexPos->setValue (pp->raw.expos); + PexPreser->setValue (pp->raw.preser);//exposi + + enableListener (); +} + +void RAWExposure::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.expos = PexPos->getValue(); + pp->raw.preser = PexPreser->getValue();//exposi + + if (pedited) { + pedited->raw.exPos = PexPos->getEditedState (); + pedited->raw.exPreser = PexPreser->getEditedState ();//exposi + } + +} + +void RAWExposure::adjusterChanged (Adjuster* a, double newval) +{ + if (listener) { + Glib::ustring value = a->getTextValue(); + + if (a == PexPos ) + listener->panelChanged (EvPreProcessExpCorrLinear, value ); + else if (a == PexPreser && ABS(PexPos->getValue()-1.0)>0.0001) // update takes long, only do it if it would have an effect + listener->panelChanged (EvPreProcessExpCorrPH, value ); + } +} + +void RAWExposure::setBatchMode(bool batchMode) +{ + ToolPanel::setBatchMode (batchMode); + PexPos->showEditedCB (); + PexPreser->showEditedCB ();//exposure +} + +void RAWExposure::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + PexPos->setDefault( defParams->raw.expos); + PexPreser->setDefault( defParams->raw.preser); + + if (pedited) { + PexPos->setDefaultEditedState( pedited->raw.exPos ? Edited : UnEdited); + PexPreser->setDefaultEditedState( pedited->raw.exPreser ? Edited : UnEdited); + } else { + PexPos->setDefaultEditedState( Irrelevant ); + PexPreser->setDefaultEditedState( Irrelevant ); + } +} + +void RAWExposure::setAdjusterBehavior (bool pexposadd, bool pexpreseradd) { + + PexPos->setAddMode(pexposadd); + PexPreser->setAddMode(pexpreseradd); +} + +void RAWExposure::trimValues (rtengine::procparams::ProcParams* pp) { + + PexPos->trimValue(pp->raw.expos); + PexPreser->trimValue(pp->raw.preser); +} diff --git a/rtgui/rawexposure.h b/rtgui/rawexposure.h index 16e0aa741..11a158105 100644 --- a/rtgui/rawexposure.h +++ b/rtgui/rawexposure.h @@ -1,48 +1,48 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _RAWEXPOSURE_H_ -#define _RAWEXPOSURE_H_ - -#include -#include "adjuster.h" -#include "toolpanel.h" -#include "../rtengine/rawimage.h" - -class RAWExposure : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { - -protected: - Adjuster* PexPos; - Adjuster* PexPreser; - -private: -// Gtk::CheckButton* PextwoGreen; -public: - - RAWExposure (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - void adjusterChanged (Adjuster* a, double newval); - void setAdjusterBehavior (bool pexposadd, bool pexpreseradd); - void trimValues (rtengine::procparams::ProcParams* pp); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _RAWEXPOSURE_H_ +#define _RAWEXPOSURE_H_ + +#include +#include "adjuster.h" +#include "toolpanel.h" +#include "../rtengine/rawimage.h" + +class RAWExposure : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { + +protected: + Adjuster* PexPos; + Adjuster* PexPreser; + +private: +// Gtk::CheckButton* PextwoGreen; +public: + + RAWExposure (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void adjusterChanged (Adjuster* a, double newval); + void setAdjusterBehavior (bool pexposadd, bool pexpreseradd); + void trimValues (rtengine::procparams::ProcParams* pp); +}; + +#endif diff --git a/rtgui/rawprocess.cc b/rtgui/rawprocess.cc index 0522f8e24..d98766506 100644 --- a/rtgui/rawprocess.cc +++ b/rtgui/rawprocess.cc @@ -1,272 +1,272 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "rawprocess.h" -#include "options.h" -#include "guiutils.h" -using namespace rtengine; -using namespace rtengine::procparams; - -RawProcess::RawProcess () : FoldableToolPanel(this) -{ - Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); - hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4); - dmethod = Gtk::manage (new MyComboBoxText ()); - for( size_t i=0; iappend_text(procparams::RAWParams::methodstring[i]); - - dmethod->set_active(0); - hb1->set_tooltip_markup (M("TP_RAW_DMETHOD_TOOLTIP")); - - hb1->pack_end (*dmethod, Gtk::PACK_EXPAND_WIDGET, 4); - pack_start( *hb1, Gtk::PACK_SHRINK, 4); - - dcbOptions = Gtk::manage (new Gtk::VBox ()); - dcbOptions->set_border_width(4); - - dcbIterations = Gtk::manage (new Adjuster (M("TP_RAW_DCBITERATIONS"),0,5,1,2)); - dcbIterations->setAdjusterListener (this); - if (dcbIterations->delay < 1000) dcbIterations->delay = 1000; - dcbIterations->show(); - dcbEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_DCBENHANCE"))); - dcbOptions->pack_start(*dcbIterations); - dcbOptions->pack_start(*dcbEnhance); - pack_start( *dcbOptions, Gtk::PACK_SHRINK, 4); - - lmmseOptions = Gtk::manage (new Gtk::VBox ()); - lmmseOptions->set_border_width(4); - - lmmseIterations = Gtk::manage (new Adjuster (M("TP_RAW_LMMSEITERATIONS"),0,6,1,2)); - lmmseIterations->setAdjusterListener (this); - lmmseIterations->set_tooltip_markup (M("TP_RAW_LMMSE_TOOLTIP")); - - if (lmmseIterations->delay < 1000) lmmseIterations->delay = 1000; - lmmseIterations->show(); - lmmseOptions->pack_start(*lmmseIterations); - pack_start( *lmmseOptions, Gtk::PACK_SHRINK, 4); - - pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); - ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"),0,5,1,0 )); - ccSteps->setAdjusterListener (this); - if (ccSteps->delay < 1000) ccSteps->delay = 1000; - ccSteps->show(); - pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); - - //pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); - //allOptions = Gtk::manage (new Gtk::VBox ()); - //allOptions->set_border_width(2); - //allEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_ALLENHANCE"))); - //allOptions->pack_start(*allEnhance); - //pack_start( *allOptions, Gtk::PACK_SHRINK, 4); - - methodconn = dmethod->signal_changed().connect( sigc::mem_fun(*this, &RawProcess::methodChanged) ); - dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &RawProcess::dcbEnhanceChanged), true); - //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &RawProcess::allEnhanceChanged), true); -} - - -void RawProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - methodconn.block (true); - dcbEnhconn.block (true); - //allEnhconn.block (true); - - dmethod->set_active(procparams::RAWParams::numMethods); - for( size_t i=0; i< procparams::RAWParams::numMethods;i++) - if( pp->raw.dmethod == procparams::RAWParams::methodstring[i]){ - dmethod->set_active(i); - oldSelection = i; - break; - } - - if(pedited ){ - ccSteps->setEditedState (pedited->raw.ccSteps ? Edited : UnEdited); - dcbIterations->setEditedState ( pedited->raw.dcbIterations ? Edited : UnEdited); - dcbEnhance->set_inconsistent(!pedited->raw.dcbEnhance); - //allEnhance->set_inconsistent(!pedited->raw.allEnhance); - lmmseIterations->setEditedState ( pedited->raw.lmmseIterations ? Edited : UnEdited); - - if( !pedited->raw.dmethod ) - dmethod->set_active(procparams::RAWParams::numMethods); // No name - } - - //allEnhance->set_active(pp->raw.all_enhance); - - dcbIterations->setValue (pp->raw.dcb_iterations); - dcbEnhance->set_active(pp->raw.dcb_enhance); - ccSteps->setValue (pp->raw.ccSteps); - if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::dcb] || - dmethod->get_active_row_number() == procparams::RAWParams::numMethods) - dcbOptions->show(); - else - dcbOptions->hide(); - - lmmseIterations->setValue (pp->raw.lmmse_iterations); - if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::lmmse] || - dmethod->get_active_row_number() == procparams::RAWParams::numMethods) - lmmseOptions->show(); - else - lmmseOptions->hide(); - - // Flase color suppression is applied to all demozaicing method, so don't hide anything - /*if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::eahd] || - pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::hphd] || - pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::vng4]) - ccSteps->show(); - else - ccSteps->hide();*/ - - lastDCBen = pp->raw.dcb_enhance; - //lastALLen = pp->raw.all_enhance; - - methodconn.block (false); - dcbEnhconn.block (false); - //allEnhconn.block (false); - - enableListener (); -} - -void RawProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.ccSteps = ccSteps->getIntValue(); - pp->raw.dcb_iterations = dcbIterations->getIntValue(); - pp->raw.dcb_enhance = dcbEnhance->get_active(); - //pp->raw.all_enhance = allEnhance->get_active(); - pp->raw.lmmse_iterations = lmmseIterations->getIntValue(); - - int currentRow = dmethod->get_active_row_number(); - if( currentRow>=0 && currentRow < procparams::RAWParams::numMethods) - pp->raw.dmethod = procparams::RAWParams::methodstring[currentRow]; - - if (pedited) { - pedited->raw.ccSteps = ccSteps->getEditedState (); - pedited->raw.dmethod = dmethod->get_active_row_number() != procparams::RAWParams::numMethods; - pedited->raw.dcbIterations = dcbIterations->getEditedState (); - pedited->raw.dcbEnhance = !dcbEnhance->get_inconsistent(); - //pedited->raw.allEnhance = !allEnhance->get_inconsistent(); - pedited->raw.lmmseIterations = lmmseIterations->getEditedState (); - - } -} - -void RawProcess::setBatchMode(bool batchMode) -{ - dmethod->append_text (M("GENERAL_UNCHANGED")); - dmethod->set_active(procparams::RAWParams::numMethods); // No name - dcbOptions->hide(); - lmmseOptions->hide(); - ToolPanel::setBatchMode (batchMode); - ccSteps->showEditedCB (); - dcbIterations->showEditedCB (); - lmmseIterations->showEditedCB (); - -} - -void RawProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) -{ - dcbIterations->setDefault( defParams->raw.dcb_iterations); - lmmseIterations->setDefault( defParams->raw.lmmse_iterations); - ccSteps->setDefault (defParams->raw.ccSteps); - if (pedited) { - dcbIterations->setDefaultEditedState( pedited->raw.dcbIterations ? Edited : UnEdited); - lmmseIterations->setDefaultEditedState( pedited->raw.lmmseIterations ? Edited : UnEdited); - ccSteps->setDefaultEditedState(pedited->raw.ccSteps ? Edited : UnEdited); - }else{ - dcbIterations->setDefaultEditedState( Irrelevant ); - lmmseIterations->setDefaultEditedState( Irrelevant ); - ccSteps->setDefaultEditedState(Irrelevant ); - } -} - -void RawProcess::adjusterChanged (Adjuster* a, double newval) -{ - if (listener) { - if (a == dcbIterations) - listener->panelChanged (EvDemosaicDCBIter, a->getTextValue() ); - else if (a == ccSteps) - listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); - else if (a == lmmseIterations) - listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() ); - - } -} - -void RawProcess::methodChanged () -{ - int curSelection = dmethod->get_active_row_number(); - if ( curSelection == procparams::RAWParams::dcb){ - dcbOptions->show(); - }else{ - dcbOptions->hide(); - } - if ( curSelection == procparams::RAWParams::lmmse){ - lmmseOptions->show(); - }else{ - lmmseOptions->hide(); - } - - Glib::ustring methodName=""; - bool ppreq = false; - if( curSelection>=0 && curSelection < procparams::RAWParams::numMethods) { - methodName = procparams::RAWParams::methodstring[curSelection]; - if (curSelection == procparams::RAWParams::mono || oldSelection == procparams::RAWParams::mono) { - ppreq = true; - } - } - oldSelection = curSelection; - - if (listener) - listener->panelChanged (ppreq ? EvDemosaicMethodPreProc : EvDemosaicMethod, methodName); -} - -void RawProcess::dcbEnhanceChanged () -{ - if (batchMode) { - if (dcbEnhance->get_inconsistent()) { - dcbEnhance->set_inconsistent (false); - dcbEnhconn.block (true); - dcbEnhance->set_active (false); - dcbEnhconn.block (false); - } - else if (lastDCBen) - dcbEnhance->set_inconsistent (true); - - lastDCBen = dcbEnhance->get_active (); - } - if (listener) - listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); -} - -/*void RawProcess::allEnhanceChanged () -{ - if (batchMode) { - if (allEnhance->get_inconsistent()) { - allEnhance->set_inconsistent (false); - allEnhconn.block (true); - allEnhance->set_active (false); - allEnhconn.block (false); - } - else if (lastALLen) - allEnhance->set_inconsistent (true); - - lastALLen = allEnhance->get_active (); - } - if (listener) - listener->panelChanged (EvDemosaicALLEnhanced, allEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); -}*/ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "rawprocess.h" +#include "options.h" +#include "guiutils.h" +using namespace rtengine; +using namespace rtengine::procparams; + +RawProcess::RawProcess () : FoldableToolPanel(this) +{ + Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); + hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4); + dmethod = Gtk::manage (new MyComboBoxText ()); + for( size_t i=0; iappend_text(procparams::RAWParams::methodstring[i]); + + dmethod->set_active(0); + hb1->set_tooltip_markup (M("TP_RAW_DMETHOD_TOOLTIP")); + + hb1->pack_end (*dmethod, Gtk::PACK_EXPAND_WIDGET, 4); + pack_start( *hb1, Gtk::PACK_SHRINK, 4); + + dcbOptions = Gtk::manage (new Gtk::VBox ()); + dcbOptions->set_border_width(4); + + dcbIterations = Gtk::manage (new Adjuster (M("TP_RAW_DCBITERATIONS"),0,5,1,2)); + dcbIterations->setAdjusterListener (this); + if (dcbIterations->delay < 1000) dcbIterations->delay = 1000; + dcbIterations->show(); + dcbEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_DCBENHANCE"))); + dcbOptions->pack_start(*dcbIterations); + dcbOptions->pack_start(*dcbEnhance); + pack_start( *dcbOptions, Gtk::PACK_SHRINK, 4); + + lmmseOptions = Gtk::manage (new Gtk::VBox ()); + lmmseOptions->set_border_width(4); + + lmmseIterations = Gtk::manage (new Adjuster (M("TP_RAW_LMMSEITERATIONS"),0,6,1,2)); + lmmseIterations->setAdjusterListener (this); + lmmseIterations->set_tooltip_markup (M("TP_RAW_LMMSE_TOOLTIP")); + + if (lmmseIterations->delay < 1000) lmmseIterations->delay = 1000; + lmmseIterations->show(); + lmmseOptions->pack_start(*lmmseIterations); + pack_start( *lmmseOptions, Gtk::PACK_SHRINK, 4); + + pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); + ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"),0,5,1,0 )); + ccSteps->setAdjusterListener (this); + if (ccSteps->delay < 1000) ccSteps->delay = 1000; + ccSteps->show(); + pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); + + //pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); + //allOptions = Gtk::manage (new Gtk::VBox ()); + //allOptions->set_border_width(2); + //allEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_ALLENHANCE"))); + //allOptions->pack_start(*allEnhance); + //pack_start( *allOptions, Gtk::PACK_SHRINK, 4); + + methodconn = dmethod->signal_changed().connect( sigc::mem_fun(*this, &RawProcess::methodChanged) ); + dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &RawProcess::dcbEnhanceChanged), true); + //allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &RawProcess::allEnhanceChanged), true); +} + + +void RawProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + methodconn.block (true); + dcbEnhconn.block (true); + //allEnhconn.block (true); + + dmethod->set_active(procparams::RAWParams::numMethods); + for( size_t i=0; i< procparams::RAWParams::numMethods;i++) + if( pp->raw.dmethod == procparams::RAWParams::methodstring[i]){ + dmethod->set_active(i); + oldSelection = i; + break; + } + + if(pedited ){ + ccSteps->setEditedState (pedited->raw.ccSteps ? Edited : UnEdited); + dcbIterations->setEditedState ( pedited->raw.dcbIterations ? Edited : UnEdited); + dcbEnhance->set_inconsistent(!pedited->raw.dcbEnhance); + //allEnhance->set_inconsistent(!pedited->raw.allEnhance); + lmmseIterations->setEditedState ( pedited->raw.lmmseIterations ? Edited : UnEdited); + + if( !pedited->raw.dmethod ) + dmethod->set_active(procparams::RAWParams::numMethods); // No name + } + + //allEnhance->set_active(pp->raw.all_enhance); + + dcbIterations->setValue (pp->raw.dcb_iterations); + dcbEnhance->set_active(pp->raw.dcb_enhance); + ccSteps->setValue (pp->raw.ccSteps); + if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::dcb] || + dmethod->get_active_row_number() == procparams::RAWParams::numMethods) + dcbOptions->show(); + else + dcbOptions->hide(); + + lmmseIterations->setValue (pp->raw.lmmse_iterations); + if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::lmmse] || + dmethod->get_active_row_number() == procparams::RAWParams::numMethods) + lmmseOptions->show(); + else + lmmseOptions->hide(); + + // Flase color suppression is applied to all demozaicing method, so don't hide anything + /*if (pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::eahd] || + pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::hphd] || + pp->raw.dmethod == procparams::RAWParams::methodstring[procparams::RAWParams::vng4]) + ccSteps->show(); + else + ccSteps->hide();*/ + + lastDCBen = pp->raw.dcb_enhance; + //lastALLen = pp->raw.all_enhance; + + methodconn.block (false); + dcbEnhconn.block (false); + //allEnhconn.block (false); + + enableListener (); +} + +void RawProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.ccSteps = ccSteps->getIntValue(); + pp->raw.dcb_iterations = dcbIterations->getIntValue(); + pp->raw.dcb_enhance = dcbEnhance->get_active(); + //pp->raw.all_enhance = allEnhance->get_active(); + pp->raw.lmmse_iterations = lmmseIterations->getIntValue(); + + int currentRow = dmethod->get_active_row_number(); + if( currentRow>=0 && currentRow < procparams::RAWParams::numMethods) + pp->raw.dmethod = procparams::RAWParams::methodstring[currentRow]; + + if (pedited) { + pedited->raw.ccSteps = ccSteps->getEditedState (); + pedited->raw.dmethod = dmethod->get_active_row_number() != procparams::RAWParams::numMethods; + pedited->raw.dcbIterations = dcbIterations->getEditedState (); + pedited->raw.dcbEnhance = !dcbEnhance->get_inconsistent(); + //pedited->raw.allEnhance = !allEnhance->get_inconsistent(); + pedited->raw.lmmseIterations = lmmseIterations->getEditedState (); + + } +} + +void RawProcess::setBatchMode(bool batchMode) +{ + dmethod->append_text (M("GENERAL_UNCHANGED")); + dmethod->set_active(procparams::RAWParams::numMethods); // No name + dcbOptions->hide(); + lmmseOptions->hide(); + ToolPanel::setBatchMode (batchMode); + ccSteps->showEditedCB (); + dcbIterations->showEditedCB (); + lmmseIterations->showEditedCB (); + +} + +void RawProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + dcbIterations->setDefault( defParams->raw.dcb_iterations); + lmmseIterations->setDefault( defParams->raw.lmmse_iterations); + ccSteps->setDefault (defParams->raw.ccSteps); + if (pedited) { + dcbIterations->setDefaultEditedState( pedited->raw.dcbIterations ? Edited : UnEdited); + lmmseIterations->setDefaultEditedState( pedited->raw.lmmseIterations ? Edited : UnEdited); + ccSteps->setDefaultEditedState(pedited->raw.ccSteps ? Edited : UnEdited); + }else{ + dcbIterations->setDefaultEditedState( Irrelevant ); + lmmseIterations->setDefaultEditedState( Irrelevant ); + ccSteps->setDefaultEditedState(Irrelevant ); + } +} + +void RawProcess::adjusterChanged (Adjuster* a, double newval) +{ + if (listener) { + if (a == dcbIterations) + listener->panelChanged (EvDemosaicDCBIter, a->getTextValue() ); + else if (a == ccSteps) + listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); + else if (a == lmmseIterations) + listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() ); + + } +} + +void RawProcess::methodChanged () +{ + int curSelection = dmethod->get_active_row_number(); + if ( curSelection == procparams::RAWParams::dcb){ + dcbOptions->show(); + }else{ + dcbOptions->hide(); + } + if ( curSelection == procparams::RAWParams::lmmse){ + lmmseOptions->show(); + }else{ + lmmseOptions->hide(); + } + + Glib::ustring methodName=""; + bool ppreq = false; + if( curSelection>=0 && curSelection < procparams::RAWParams::numMethods) { + methodName = procparams::RAWParams::methodstring[curSelection]; + if (curSelection == procparams::RAWParams::mono || oldSelection == procparams::RAWParams::mono) { + ppreq = true; + } + } + oldSelection = curSelection; + + if (listener) + listener->panelChanged (ppreq ? EvDemosaicMethodPreProc : EvDemosaicMethod, methodName); +} + +void RawProcess::dcbEnhanceChanged () +{ + if (batchMode) { + if (dcbEnhance->get_inconsistent()) { + dcbEnhance->set_inconsistent (false); + dcbEnhconn.block (true); + dcbEnhance->set_active (false); + dcbEnhconn.block (false); + } + else if (lastDCBen) + dcbEnhance->set_inconsistent (true); + + lastDCBen = dcbEnhance->get_active (); + } + if (listener) + listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); +} + +/*void RawProcess::allEnhanceChanged () +{ + if (batchMode) { + if (allEnhance->get_inconsistent()) { + allEnhance->set_inconsistent (false); + allEnhconn.block (true); + allEnhance->set_active (false); + allEnhconn.block (false); + } + else if (lastALLen) + allEnhance->set_inconsistent (true); + + lastALLen = allEnhance->get_active (); + } + if (listener) + listener->panelChanged (EvDemosaicALLEnhanced, allEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); +}*/ diff --git a/rtgui/rawprocess.h b/rtgui/rawprocess.h index f88c7bdc0..f3c005219 100644 --- a/rtgui/rawprocess.h +++ b/rtgui/rawprocess.h @@ -1,63 +1,63 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _RAWPROCESS_H_ -#define _RAWPROCESS_H_ - -#include -#include "adjuster.h" -#include "guiutils.h" -#include "toolpanel.h" - - -class RawProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel{ - - protected: - - MyComboBoxText* dmethod; - Gtk::Label* methodl; - Adjuster* ccSteps; - Gtk::VBox *dcbOptions; - Adjuster* dcbIterations; - Gtk::CheckButton* dcbEnhance; - //Gtk::VBox *allOptions; - //Gtk::CheckButton* allEnhance; - Gtk::VBox *lmmseOptions; - Adjuster* lmmseIterations; - - bool lastDCBen; - int oldSelection; - //bool lastALLen; - sigc::connection methodconn,dcbEnhconn; //,allEnhconn; - public: - - RawProcess (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - - void methodChanged (); - void adjusterChanged (Adjuster* a, double newval); - void dcbEnhanceChanged(); - //void allEnhanceChanged(); - -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _RAWPROCESS_H_ +#define _RAWPROCESS_H_ + +#include +#include "adjuster.h" +#include "guiutils.h" +#include "toolpanel.h" + + +class RawProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel{ + + protected: + + MyComboBoxText* dmethod; + Gtk::Label* methodl; + Adjuster* ccSteps; + Gtk::VBox *dcbOptions; + Adjuster* dcbIterations; + Gtk::CheckButton* dcbEnhance; + //Gtk::VBox *allOptions; + //Gtk::CheckButton* allEnhance; + Gtk::VBox *lmmseOptions; + Adjuster* lmmseIterations; + + bool lastDCBen; + int oldSelection; + //bool lastALLen; + sigc::connection methodconn,dcbEnhconn; //,allEnhconn; + public: + + RawProcess (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + + void methodChanged (); + void adjusterChanged (Adjuster* a, double newval); + void dcbEnhanceChanged(); + //void allEnhanceChanged(); + +}; + +#endif diff --git a/rtgui/resize.cc b/rtgui/resize.cc index 58d4c8ac5..231f84659 100644 --- a/rtgui/resize.cc +++ b/rtgui/resize.cc @@ -1,615 +1,615 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "resize.h" -#include "guiutils.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), false, true), maxw(100000), maxh(100000) -{ - - cropw = 0; - croph = 0; - - Gtk::Table* combos = Gtk::manage (new Gtk::Table (2, 2)); - Gtk::Label *label = NULL; - - appliesTo = Gtk::manage (new MyComboBoxText ()); - appliesTo->append_text (M("TP_RESIZE_CROPPEDAREA")); - appliesTo->append_text (M("TP_RESIZE_FULLIMAGE")); - appliesTo->set_active (0); - - label = Gtk::manage (new Gtk::Label (M("TP_RESIZE_APPLIESTO"))); - label->set_alignment(0., 0.); - combos->attach (*label, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); - combos->attach (*appliesTo, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); - - // See Resize::methodChanged() when adding a new method. - method = Gtk::manage (new MyComboBoxText ()); - method->append_text (M("TP_RESIZE_LANCZOS")); - method->append_text (M("TP_RESIZE_NEAREST")); - method->set_active (0); - - label = Gtk::manage (new Gtk::Label (M("TP_RESIZE_METHOD"))); - label->set_alignment(0., 0.); - combos->attach (*label, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 2, 2); - combos->attach (*method, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); - - spec = Gtk::manage (new MyComboBoxText ()); - spec->append_text (M("TP_RESIZE_SCALE")); - spec->append_text (M("TP_RESIZE_WIDTH")); - spec->append_text (M("TP_RESIZE_HEIGHT")); - spec->append_text (M("TP_RESIZE_FITBOX")); - spec->set_active (0); - - label = Gtk::manage (new Gtk::Label (M("TP_RESIZE_SPECIFY"))); - label->set_alignment(0., 0.); - combos->attach (*label, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 2, 2); - combos->attach (*spec, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); - - pack_start (*combos, Gtk::PACK_SHRINK, 4); - - scale = new Adjuster (M("TP_RESIZE_SCALE"), 0.01, 4, 0.01, 1.); - scale->setAdjusterListener (this); - - pack_start (*scale, Gtk::PACK_SHRINK, 4); - - sizeBox = Gtk::manage (new Gtk::VBox ()); - - Gtk::HBox* sbox = Gtk::manage (new Gtk::HBox ()); - Gtk::HBox* wbox = Gtk::manage (new Gtk::HBox ()); - Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox ()); - w = Gtk::manage (new MySpinButton ()); - h = Gtk::manage (new MySpinButton ()); - wbox->set_spacing(3); - wbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_W"))), Gtk::PACK_SHRINK, 0); - wbox->pack_start (*w); - hbox->set_spacing(3); - hbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_H"))), Gtk::PACK_SHRINK, 0); - hbox->pack_start (*h); - sbox->set_spacing(4); - sbox->pack_start (*wbox); - sbox->pack_start (*hbox); - - sizeBox->pack_start (*sbox, Gtk::PACK_SHRINK, 0); - sizeBox->show_all (); - sizeBox->reference (); - - w->set_digits (0); - w->set_increments (1, 100); - w->set_value (800); - w->set_range (32, 4 * maxw); - - h->set_digits (0); - h->set_increments (1, 100); - h->set_value (600); - h->set_range (32, 4 * maxh); - - wconn = w->signal_value_changed().connect ( sigc::mem_fun(*this, &Resize::entryWChanged), true); - hconn = h->signal_value_changed().connect ( sigc::mem_fun(*this, &Resize::entryHChanged), true); - aconn = appliesTo->signal_changed().connect ( sigc::mem_fun(*this, &Resize::appliesToChanged) ); - method->signal_changed().connect ( sigc::mem_fun(*this, &Resize::methodChanged) ); - sconn = spec->signal_changed().connect ( sigc::mem_fun(*this, &Resize::specChanged) ); - - packBox = Gtk::manage (new ToolParamBlock ()); - pack_end (*packBox); - packBox->hide(); - packBox->set_tooltip_markup (M("TP_PRSHARPENING_TOOLTIP")); - - show_all(); -} - -Resize::~Resize () -{ - - delete scale; - delete sizeBox; -} - -void Resize::read (const ProcParams* pp, const ParamsEdited* pedited) -{ - - disableListener (); - aconn.block (true); - wconn.block (true); - hconn.block (true); - sconn.block (true); - scale->block(true); - - scale->setValue (pp->resize.scale); - w->set_value (pp->resize.width); - h->set_value (pp->resize.height); - setEnabled (pp->resize.enabled); - spec->set_active (pp->resize.dataspec); - updateGUI(); - - appliesTo->set_active (0); - - if (pp->resize.appliesTo == "Cropped area") { - appliesTo->set_active (0); - } else if (pp->resize.appliesTo == "Full image") { - appliesTo->set_active (1); - } - - if (pp->resize.method == "Lanczos") { - method->set_active (0); - } else if (pp->resize.method == "Nearest") { - method->set_active (1); - } else { - method->set_active (0); - } - - wDirty = false; - hDirty = false; - - if (pedited) { - wDirty = pedited->resize.width; - hDirty = pedited->resize.height; - scale->setEditedState (pedited->resize.scale ? Edited : UnEdited); - - if (!pedited->resize.appliesTo) { - appliesTo->set_active (2); - } - - if (!pedited->resize.method) { - method->set_active (3); - } - - if (!pedited->resize.dataspec) { - spec->set_active (4); - } - - set_inconsistent (multiImage && !pedited->resize.enabled); - } - - scale->block(false); - sconn.block (false); - wconn.block (false); - hconn.block (false); - aconn.block (false); - enableListener (); -} - -void Resize::write (ProcParams* pp, ParamsEdited* pedited) -{ - int dataSpec = spec->get_active_row_number(); - - pp->resize.scale = scale->getValue(); - - pp->resize.appliesTo = "Cropped area"; - - if (appliesTo->get_active_row_number() == 0) { - pp->resize.appliesTo = "Cropped area"; - } else if (appliesTo->get_active_row_number() == 1) { - pp->resize.appliesTo = "Full image"; - } - - pp->resize.method = "Lanczos"; - - if (method->get_active_row_number() == 0) { - pp->resize.method = "Lanczos"; - } else if (method->get_active_row_number() == 1) { - pp->resize.method = "Nearest"; - } - - pp->resize.dataspec = dataSpec; - pp->resize.width = w->get_value_as_int (); - pp->resize.height = h->get_value_as_int (); - pp->resize.enabled = getEnabled (); - //printf(" L:%d H:%d\n", pp->resize.width, pp->resize.height); - - if (pedited) { - pedited->resize.enabled = !get_inconsistent(); - pedited->resize.dataspec = dataSpec != 4; - pedited->resize.appliesTo = appliesTo->get_active_row_number() != 2; - pedited->resize.method = method->get_active_row_number() != 3; - - if (pedited->resize.dataspec) { - pedited->resize.scale = scale->getEditedState (); - pedited->resize.width = wDirty; - pedited->resize.height = hDirty; - } else { - pedited->resize.scale = false; - pedited->resize.width = false; - pedited->resize.height = false; - } - } -} - -void Resize::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) -{ - - scale->setDefault (defParams->resize.scale); - - if (pedited) { - scale->setDefaultEditedState (pedited->resize.scale ? Edited : UnEdited); - } else { - scale->setDefaultEditedState (Irrelevant); - } -} - -void Resize::adjusterChanged (Adjuster* a, double newval) -{ - - if (!batchMode) { - wconn.block (true); - hconn.block (true); - h->set_value ((croph && appliesTo->get_active_row_number() == 0 ? croph : maxh) * a->getValue ()); - w->set_value ((cropw && appliesTo->get_active_row_number() == 0 ? cropw : maxw) * a->getValue ()); - wconn.block (false); - hconn.block (false); - } - - if (listener && (getEnabled () || batchMode)) { - listener->panelChanged (EvResizeScale, Glib::ustring::format (std::setw(5), std::fixed, std::setprecision(2), scale->getValue())); - } -} - -int Resize::getComputedWidth() -{ - - if (cropw && appliesTo->get_active_row_number() == 0) - // we use the crop dimensions - { - return (int)((double)(cropw) * (h->get_value() / (double)(croph)) + 0.5); - } else - // we use the image dimensions - { - return (int)((double)(maxw) * (h->get_value() / (double)(maxh)) + 0.5); - } -} - -int Resize::getComputedHeight() -{ - - if (croph && appliesTo->get_active_row_number() == 0) - // we use the crop dimensions - { - return (int)((double)(croph) * (w->get_value() / (double)(cropw)) + 0.5); - } else - // we use the image dimensions - { - return (int)((double)(maxh) * (w->get_value() / (double)(maxw)) + 0.5); - } -} - -void Resize::appliesToChanged () -{ - - //printf("\nPASSAGE EN MODE \"%s\"\n\n", appliesTo->get_active_text().c_str()); - setDimensions(); - - if (listener && (getEnabled () || batchMode)) { - //printf("Appel du listener\n"); - listener->panelChanged (EvResizeAppliesTo, appliesTo->get_active_text()); - } -} - -void Resize::methodChanged () -{ - - if (listener && (getEnabled () || batchMode)) { - listener->panelChanged (EvResizeMethod, method->get_active_text()); - } - - // Post-resize Sharpening assumes the image is in Lab space, and currently Lanczos is the only method which uses that space, and Lanczos is on row 0. - if (method->get_active_row_number() == 0) { - packBox->set_sensitive(true); - } else { - packBox->set_sensitive(false); - } -} - -void Resize::update (bool isCropped, int cw, int ch, int ow, int oh) -{ - - // updating crop values now - if (isCropped) { - cropw = cw; - croph = ch; - } else { - cropw = 0; - croph = 0; - } - - // updating the full image dimensions - if (ow && oh) { - maxw = ow; - maxh = oh; - } - - // updating the GUI synchronously - setDimensions(); -} - -void Resize::sizeChanged (int mw, int mh, int ow, int oh) -{ - - // updating max values now - maxw = ow; - maxh = oh; - - // updating the GUI synchronously - setDimensions(); -} - -void Resize::setDimensions () -{ - - int refw, refh; - - wconn.block (true); - hconn.block (true); - scale->block(true); - - if (appliesTo->get_active_row_number() == 0 && cropw) { - // Applies to Cropped area - refw = cropw; - refh = croph; - } else { - // Applies to Full image or crop is disabled - refw = maxw; - refh = maxh; - } - - GThreadLock lock; - w->set_range (32, 4 * refw); - h->set_range (32, 4 * refh); - - double tmpScale; - - switch (spec->get_active_row_number()) { - case (0): // Scale mode - w->set_value((double)((int)( (double)(refw) * scale->getValue() + 0.5) )); - h->set_value((double)((int)( (double)(refh) * scale->getValue() + 0.5) )); - break; - - case (1): // Width mode - tmpScale = w->get_value() / (double)refw; - scale->setValue (tmpScale); - h->set_value((double)((int)( (double)(refh) * tmpScale + 0.5) )); - break; - - case (2): // Height mode - tmpScale = h->get_value() / (double)refh; - scale->setValue (tmpScale); - w->set_value((double)((int)( (double)(refw) * tmpScale + 0.5) )); - break; - - case (3): { // Bounding box mode - double wSliderValue = w->get_value(); - double hSliderValue = h->get_value(); - - if ( (wSliderValue / hSliderValue) < ((double)refw / (double)refh)) { - tmpScale = wSliderValue / (double)refw; - } else { - tmpScale = hSliderValue / (double)refh; - } - - scale->setValue (tmpScale); - break; - } - - default: - break; - } - - scale->block(false); - wconn.block (false); - hconn.block (false); -} - -void Resize::fitBoxScale() -{ - double tmpScale; - double neww = w->get_value (); - double newh = h->get_value (); - - if (cropw && appliesTo->get_active_row_number() == 0) { - // we use the crop dimensions - if (((double)(cropw) / (double)(croph)) > (neww / newh)) { - // the new scale is given by the image width - tmpScale = neww / (double)(cropw); - } else { - // the new scale is given by the image height - tmpScale = newh / (double)(croph); - } - } else { - // we use the image dimensions - if (((double)(maxw) / (double)(maxh)) > (neww / newh)) { - // the new scale is given by the image width - tmpScale = neww / (double)(maxw); - } else { - // the new scale is given by the image height - tmpScale = newh / (double)(maxh); - } - } - - scale->setValue (tmpScale); -} - -void Resize::entryWChanged () -{ - - wDirty = true; - - // updating width - if (!batchMode) { - if (spec->get_active_row_number() == 3) { - // Fit box mode - fitBoxScale(); - } else { - // Other modes - hconn.block (true); - scale->block (true); - - h->set_value ((double)(getComputedHeight())); - scale->setValue (w->get_value () / (cropw && appliesTo->get_active_row_number() == 0 ? (double)cropw : (double)maxw)); - - scale->block (false); - hconn.block (false); - } - } - - if (listener) { - if (spec->get_active_row_number() == 3) { - notifyBBox(); - } else { - if (getEnabled () || batchMode) { - listener->panelChanged (EvResizeWidth, Glib::ustring::format (w->get_value_as_int())); - } - } - } -} - -void Resize::entryHChanged () -{ - - hDirty = true; - - if (!batchMode && listener) { - if (spec->get_active_row_number() == 3) { - // Fit box mode - fitBoxScale(); - } else { - // Other modes - wconn.block (true); - scale->block (true); - - w->set_value ((double)(getComputedWidth())); - scale->setValue (h->get_value () / (croph && appliesTo->get_active_row_number() == 0 ? (double)croph : (double)maxh)); - - scale->block (false); - wconn.block (false); - } - } - - if (listener) { - if (spec->get_active_row_number() == 3) { - notifyBBox(); - } else { - if (getEnabled () || batchMode) { - listener->panelChanged (EvResizeHeight, Glib::ustring::format (h->get_value_as_int())); - } - } - } -} - -void Resize::specChanged () -{ - - switch (spec->get_active_row_number()) { - case (0): - // Scale mode - scale->sliderChanged (); - break; - - case (1): - // Width mode - w->set_value((double)(getComputedWidth())); - entryWChanged (); - break; - - case (2): - // Height mode - h->set_value((double)(getComputedHeight())); - entryHChanged (); - break; - - case (3): - // Bounding box mode - notifyBBox(); - break; - - default: - break; - } - - updateGUI(); -} - -void Resize::updateGUI () -{ - - removeIfThere (this, scale, false); - removeIfThere (this, sizeBox, false); - - switch (spec->get_active_row_number()) { - case (0): - // Scale mode - pack_start (*scale, Gtk::PACK_SHRINK, 4); - break; - - case (1): - // Width mode - pack_start (*sizeBox, Gtk::PACK_SHRINK, 4); - w->set_sensitive (true); - h->set_sensitive (false); - break; - - case (2): - // Height mode - pack_start (*sizeBox, Gtk::PACK_SHRINK, 4); - w->set_sensitive (false); - h->set_sensitive (true); - break; - - case (3): - // Bounding box mode - pack_start (*sizeBox, Gtk::PACK_SHRINK, 4); - w->set_sensitive (true); - h->set_sensitive (true); - break; - - default: - break; - } -} - -void Resize::notifyBBox() -{ - if (listener && (getEnabled () || batchMode)) { - listener->panelChanged (EvResizeBoundingBox, Glib::ustring::compose("(%1x%2)", (int)w->get_value(), (int)h->get_value() )); - } -} - -void Resize::setBatchMode (bool batchMode) -{ - - method->append_text (M("GENERAL_UNCHANGED")); - spec->append_text (M("GENERAL_UNCHANGED")); - ToolPanel::setBatchMode (batchMode); - scale->showEditedCB (); -} - -void Resize::enabledChanged () -{ - - if (listener) { - if (get_inconsistent()) { - listener->panelChanged (EvResizeEnabled, M("GENERAL_UNCHANGED")); - } else if (getEnabled()) { - listener->panelChanged (EvResizeEnabled, M("GENERAL_ENABLED")); - } else { - listener->panelChanged (EvResizeEnabled, M("GENERAL_DISABLED")); - } - } -} - +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "resize.h" +#include "guiutils.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), false, true), maxw(100000), maxh(100000) +{ + + cropw = 0; + croph = 0; + + Gtk::Table* combos = Gtk::manage (new Gtk::Table (2, 2)); + Gtk::Label *label = NULL; + + appliesTo = Gtk::manage (new MyComboBoxText ()); + appliesTo->append_text (M("TP_RESIZE_CROPPEDAREA")); + appliesTo->append_text (M("TP_RESIZE_FULLIMAGE")); + appliesTo->set_active (0); + + label = Gtk::manage (new Gtk::Label (M("TP_RESIZE_APPLIESTO"))); + label->set_alignment(0., 0.); + combos->attach (*label, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + combos->attach (*appliesTo, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + // See Resize::methodChanged() when adding a new method. + method = Gtk::manage (new MyComboBoxText ()); + method->append_text (M("TP_RESIZE_LANCZOS")); + method->append_text (M("TP_RESIZE_NEAREST")); + method->set_active (0); + + label = Gtk::manage (new Gtk::Label (M("TP_RESIZE_METHOD"))); + label->set_alignment(0., 0.); + combos->attach (*label, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + combos->attach (*method, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + spec = Gtk::manage (new MyComboBoxText ()); + spec->append_text (M("TP_RESIZE_SCALE")); + spec->append_text (M("TP_RESIZE_WIDTH")); + spec->append_text (M("TP_RESIZE_HEIGHT")); + spec->append_text (M("TP_RESIZE_FITBOX")); + spec->set_active (0); + + label = Gtk::manage (new Gtk::Label (M("TP_RESIZE_SPECIFY"))); + label->set_alignment(0., 0.); + combos->attach (*label, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 2, 2); + combos->attach (*spec, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, 2, 2); + + pack_start (*combos, Gtk::PACK_SHRINK, 4); + + scale = new Adjuster (M("TP_RESIZE_SCALE"), 0.01, 4, 0.01, 1.); + scale->setAdjusterListener (this); + + pack_start (*scale, Gtk::PACK_SHRINK, 4); + + sizeBox = Gtk::manage (new Gtk::VBox ()); + + Gtk::HBox* sbox = Gtk::manage (new Gtk::HBox ()); + Gtk::HBox* wbox = Gtk::manage (new Gtk::HBox ()); + Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox ()); + w = Gtk::manage (new MySpinButton ()); + h = Gtk::manage (new MySpinButton ()); + wbox->set_spacing(3); + wbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_W"))), Gtk::PACK_SHRINK, 0); + wbox->pack_start (*w); + hbox->set_spacing(3); + hbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_H"))), Gtk::PACK_SHRINK, 0); + hbox->pack_start (*h); + sbox->set_spacing(4); + sbox->pack_start (*wbox); + sbox->pack_start (*hbox); + + sizeBox->pack_start (*sbox, Gtk::PACK_SHRINK, 0); + sizeBox->show_all (); + sizeBox->reference (); + + w->set_digits (0); + w->set_increments (1, 100); + w->set_value (800); + w->set_range (32, 4 * maxw); + + h->set_digits (0); + h->set_increments (1, 100); + h->set_value (600); + h->set_range (32, 4 * maxh); + + wconn = w->signal_value_changed().connect ( sigc::mem_fun(*this, &Resize::entryWChanged), true); + hconn = h->signal_value_changed().connect ( sigc::mem_fun(*this, &Resize::entryHChanged), true); + aconn = appliesTo->signal_changed().connect ( sigc::mem_fun(*this, &Resize::appliesToChanged) ); + method->signal_changed().connect ( sigc::mem_fun(*this, &Resize::methodChanged) ); + sconn = spec->signal_changed().connect ( sigc::mem_fun(*this, &Resize::specChanged) ); + + packBox = Gtk::manage (new ToolParamBlock ()); + pack_end (*packBox); + packBox->hide(); + packBox->set_tooltip_markup (M("TP_PRSHARPENING_TOOLTIP")); + + show_all(); +} + +Resize::~Resize () +{ + + delete scale; + delete sizeBox; +} + +void Resize::read (const ProcParams* pp, const ParamsEdited* pedited) +{ + + disableListener (); + aconn.block (true); + wconn.block (true); + hconn.block (true); + sconn.block (true); + scale->block(true); + + scale->setValue (pp->resize.scale); + w->set_value (pp->resize.width); + h->set_value (pp->resize.height); + setEnabled (pp->resize.enabled); + spec->set_active (pp->resize.dataspec); + updateGUI(); + + appliesTo->set_active (0); + + if (pp->resize.appliesTo == "Cropped area") { + appliesTo->set_active (0); + } else if (pp->resize.appliesTo == "Full image") { + appliesTo->set_active (1); + } + + if (pp->resize.method == "Lanczos") { + method->set_active (0); + } else if (pp->resize.method == "Nearest") { + method->set_active (1); + } else { + method->set_active (0); + } + + wDirty = false; + hDirty = false; + + if (pedited) { + wDirty = pedited->resize.width; + hDirty = pedited->resize.height; + scale->setEditedState (pedited->resize.scale ? Edited : UnEdited); + + if (!pedited->resize.appliesTo) { + appliesTo->set_active (2); + } + + if (!pedited->resize.method) { + method->set_active (3); + } + + if (!pedited->resize.dataspec) { + spec->set_active (4); + } + + set_inconsistent (multiImage && !pedited->resize.enabled); + } + + scale->block(false); + sconn.block (false); + wconn.block (false); + hconn.block (false); + aconn.block (false); + enableListener (); +} + +void Resize::write (ProcParams* pp, ParamsEdited* pedited) +{ + int dataSpec = spec->get_active_row_number(); + + pp->resize.scale = scale->getValue(); + + pp->resize.appliesTo = "Cropped area"; + + if (appliesTo->get_active_row_number() == 0) { + pp->resize.appliesTo = "Cropped area"; + } else if (appliesTo->get_active_row_number() == 1) { + pp->resize.appliesTo = "Full image"; + } + + pp->resize.method = "Lanczos"; + + if (method->get_active_row_number() == 0) { + pp->resize.method = "Lanczos"; + } else if (method->get_active_row_number() == 1) { + pp->resize.method = "Nearest"; + } + + pp->resize.dataspec = dataSpec; + pp->resize.width = w->get_value_as_int (); + pp->resize.height = h->get_value_as_int (); + pp->resize.enabled = getEnabled (); + //printf(" L:%d H:%d\n", pp->resize.width, pp->resize.height); + + if (pedited) { + pedited->resize.enabled = !get_inconsistent(); + pedited->resize.dataspec = dataSpec != 4; + pedited->resize.appliesTo = appliesTo->get_active_row_number() != 2; + pedited->resize.method = method->get_active_row_number() != 3; + + if (pedited->resize.dataspec) { + pedited->resize.scale = scale->getEditedState (); + pedited->resize.width = wDirty; + pedited->resize.height = hDirty; + } else { + pedited->resize.scale = false; + pedited->resize.width = false; + pedited->resize.height = false; + } + } +} + +void Resize::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) +{ + + scale->setDefault (defParams->resize.scale); + + if (pedited) { + scale->setDefaultEditedState (pedited->resize.scale ? Edited : UnEdited); + } else { + scale->setDefaultEditedState (Irrelevant); + } +} + +void Resize::adjusterChanged (Adjuster* a, double newval) +{ + + if (!batchMode) { + wconn.block (true); + hconn.block (true); + h->set_value ((croph && appliesTo->get_active_row_number() == 0 ? croph : maxh) * a->getValue ()); + w->set_value ((cropw && appliesTo->get_active_row_number() == 0 ? cropw : maxw) * a->getValue ()); + wconn.block (false); + hconn.block (false); + } + + if (listener && (getEnabled () || batchMode)) { + listener->panelChanged (EvResizeScale, Glib::ustring::format (std::setw(5), std::fixed, std::setprecision(2), scale->getValue())); + } +} + +int Resize::getComputedWidth() +{ + + if (cropw && appliesTo->get_active_row_number() == 0) + // we use the crop dimensions + { + return (int)((double)(cropw) * (h->get_value() / (double)(croph)) + 0.5); + } else + // we use the image dimensions + { + return (int)((double)(maxw) * (h->get_value() / (double)(maxh)) + 0.5); + } +} + +int Resize::getComputedHeight() +{ + + if (croph && appliesTo->get_active_row_number() == 0) + // we use the crop dimensions + { + return (int)((double)(croph) * (w->get_value() / (double)(cropw)) + 0.5); + } else + // we use the image dimensions + { + return (int)((double)(maxh) * (w->get_value() / (double)(maxw)) + 0.5); + } +} + +void Resize::appliesToChanged () +{ + + //printf("\nPASSAGE EN MODE \"%s\"\n\n", appliesTo->get_active_text().c_str()); + setDimensions(); + + if (listener && (getEnabled () || batchMode)) { + //printf("Appel du listener\n"); + listener->panelChanged (EvResizeAppliesTo, appliesTo->get_active_text()); + } +} + +void Resize::methodChanged () +{ + + if (listener && (getEnabled () || batchMode)) { + listener->panelChanged (EvResizeMethod, method->get_active_text()); + } + + // Post-resize Sharpening assumes the image is in Lab space, and currently Lanczos is the only method which uses that space, and Lanczos is on row 0. + if (method->get_active_row_number() == 0) { + packBox->set_sensitive(true); + } else { + packBox->set_sensitive(false); + } +} + +void Resize::update (bool isCropped, int cw, int ch, int ow, int oh) +{ + + // updating crop values now + if (isCropped) { + cropw = cw; + croph = ch; + } else { + cropw = 0; + croph = 0; + } + + // updating the full image dimensions + if (ow && oh) { + maxw = ow; + maxh = oh; + } + + // updating the GUI synchronously + setDimensions(); +} + +void Resize::sizeChanged (int mw, int mh, int ow, int oh) +{ + + // updating max values now + maxw = ow; + maxh = oh; + + // updating the GUI synchronously + setDimensions(); +} + +void Resize::setDimensions () +{ + + int refw, refh; + + wconn.block (true); + hconn.block (true); + scale->block(true); + + if (appliesTo->get_active_row_number() == 0 && cropw) { + // Applies to Cropped area + refw = cropw; + refh = croph; + } else { + // Applies to Full image or crop is disabled + refw = maxw; + refh = maxh; + } + + GThreadLock lock; + w->set_range (32, 4 * refw); + h->set_range (32, 4 * refh); + + double tmpScale; + + switch (spec->get_active_row_number()) { + case (0): // Scale mode + w->set_value((double)((int)( (double)(refw) * scale->getValue() + 0.5) )); + h->set_value((double)((int)( (double)(refh) * scale->getValue() + 0.5) )); + break; + + case (1): // Width mode + tmpScale = w->get_value() / (double)refw; + scale->setValue (tmpScale); + h->set_value((double)((int)( (double)(refh) * tmpScale + 0.5) )); + break; + + case (2): // Height mode + tmpScale = h->get_value() / (double)refh; + scale->setValue (tmpScale); + w->set_value((double)((int)( (double)(refw) * tmpScale + 0.5) )); + break; + + case (3): { // Bounding box mode + double wSliderValue = w->get_value(); + double hSliderValue = h->get_value(); + + if ( (wSliderValue / hSliderValue) < ((double)refw / (double)refh)) { + tmpScale = wSliderValue / (double)refw; + } else { + tmpScale = hSliderValue / (double)refh; + } + + scale->setValue (tmpScale); + break; + } + + default: + break; + } + + scale->block(false); + wconn.block (false); + hconn.block (false); +} + +void Resize::fitBoxScale() +{ + double tmpScale; + double neww = w->get_value (); + double newh = h->get_value (); + + if (cropw && appliesTo->get_active_row_number() == 0) { + // we use the crop dimensions + if (((double)(cropw) / (double)(croph)) > (neww / newh)) { + // the new scale is given by the image width + tmpScale = neww / (double)(cropw); + } else { + // the new scale is given by the image height + tmpScale = newh / (double)(croph); + } + } else { + // we use the image dimensions + if (((double)(maxw) / (double)(maxh)) > (neww / newh)) { + // the new scale is given by the image width + tmpScale = neww / (double)(maxw); + } else { + // the new scale is given by the image height + tmpScale = newh / (double)(maxh); + } + } + + scale->setValue (tmpScale); +} + +void Resize::entryWChanged () +{ + + wDirty = true; + + // updating width + if (!batchMode) { + if (spec->get_active_row_number() == 3) { + // Fit box mode + fitBoxScale(); + } else { + // Other modes + hconn.block (true); + scale->block (true); + + h->set_value ((double)(getComputedHeight())); + scale->setValue (w->get_value () / (cropw && appliesTo->get_active_row_number() == 0 ? (double)cropw : (double)maxw)); + + scale->block (false); + hconn.block (false); + } + } + + if (listener) { + if (spec->get_active_row_number() == 3) { + notifyBBox(); + } else { + if (getEnabled () || batchMode) { + listener->panelChanged (EvResizeWidth, Glib::ustring::format (w->get_value_as_int())); + } + } + } +} + +void Resize::entryHChanged () +{ + + hDirty = true; + + if (!batchMode && listener) { + if (spec->get_active_row_number() == 3) { + // Fit box mode + fitBoxScale(); + } else { + // Other modes + wconn.block (true); + scale->block (true); + + w->set_value ((double)(getComputedWidth())); + scale->setValue (h->get_value () / (croph && appliesTo->get_active_row_number() == 0 ? (double)croph : (double)maxh)); + + scale->block (false); + wconn.block (false); + } + } + + if (listener) { + if (spec->get_active_row_number() == 3) { + notifyBBox(); + } else { + if (getEnabled () || batchMode) { + listener->panelChanged (EvResizeHeight, Glib::ustring::format (h->get_value_as_int())); + } + } + } +} + +void Resize::specChanged () +{ + + switch (spec->get_active_row_number()) { + case (0): + // Scale mode + scale->sliderChanged (); + break; + + case (1): + // Width mode + w->set_value((double)(getComputedWidth())); + entryWChanged (); + break; + + case (2): + // Height mode + h->set_value((double)(getComputedHeight())); + entryHChanged (); + break; + + case (3): + // Bounding box mode + notifyBBox(); + break; + + default: + break; + } + + updateGUI(); +} + +void Resize::updateGUI () +{ + + removeIfThere (this, scale, false); + removeIfThere (this, sizeBox, false); + + switch (spec->get_active_row_number()) { + case (0): + // Scale mode + pack_start (*scale, Gtk::PACK_SHRINK, 4); + break; + + case (1): + // Width mode + pack_start (*sizeBox, Gtk::PACK_SHRINK, 4); + w->set_sensitive (true); + h->set_sensitive (false); + break; + + case (2): + // Height mode + pack_start (*sizeBox, Gtk::PACK_SHRINK, 4); + w->set_sensitive (false); + h->set_sensitive (true); + break; + + case (3): + // Bounding box mode + pack_start (*sizeBox, Gtk::PACK_SHRINK, 4); + w->set_sensitive (true); + h->set_sensitive (true); + break; + + default: + break; + } +} + +void Resize::notifyBBox() +{ + if (listener && (getEnabled () || batchMode)) { + listener->panelChanged (EvResizeBoundingBox, Glib::ustring::compose("(%1x%2)", (int)w->get_value(), (int)h->get_value() )); + } +} + +void Resize::setBatchMode (bool batchMode) +{ + + method->append_text (M("GENERAL_UNCHANGED")); + spec->append_text (M("GENERAL_UNCHANGED")); + ToolPanel::setBatchMode (batchMode); + scale->showEditedCB (); +} + +void Resize::enabledChanged () +{ + + if (listener) { + if (get_inconsistent()) { + listener->panelChanged (EvResizeEnabled, M("GENERAL_UNCHANGED")); + } else if (getEnabled()) { + listener->panelChanged (EvResizeEnabled, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvResizeEnabled, M("GENERAL_DISABLED")); + } + } +} + diff --git a/rtgui/rgbcurves.cc b/rtgui/rgbcurves.cc index 64b4fb93f..e52ffe83a 100644 --- a/rtgui/rgbcurves.cc +++ b/rtgui/rgbcurves.cc @@ -1,180 +1,180 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "rgbcurves.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -RGBCurves::RGBCurves () : FoldableToolPanel(this, "rgbcurves", M("TP_RGBCURVES_LABEL")) { - - lumamode = Gtk::manage (new Gtk::CheckButton (M("TP_RGBCURVES_LUMAMODE"))); - lumamode->set_tooltip_markup (M("TP_RGBCURVES_LUMAMODE_TOOLTIP")); - lumamode->set_active (false); - lumamode->show (); - pack_start (*lumamode); - - Gtk::HSeparator *hsep1 = Gtk::manage (new Gtk::HSeparator()); - hsep1->show (); - pack_start (*hsep1); - - lumamodeConn = lumamode->signal_toggled().connect( sigc::mem_fun(*this, &RGBCurves::lumamodeChanged) ); - - std::vector milestones; - - curveEditorG = new CurveEditorGroup (options.lastRgbCurvesDir, M("TP_RGBCURVES_CHANNEL")); - curveEditorG->setCurveListener (this); - - Rshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_RGBCURVES_RED"))); - Rshape->setEditID(EUID_RGB_R, BT_SINGLEPLANE_FLOAT); - milestones.push_back( GradientMilestone(0.0, 0.0, 0.0, 0.0) ); - milestones.push_back( GradientMilestone(1.0, 1.0, 0.0, 0.0) ); - Rshape->setBottomBarBgGradient(milestones); - Rshape->setLeftBarBgGradient(milestones); - - milestones[1].r = 0.0; milestones[1].g = 1.0; - Gshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_RGBCURVES_GREEN"))); - Gshape->setEditID(EUID_RGB_G, BT_SINGLEPLANE_FLOAT); - Gshape->setBottomBarBgGradient(milestones); - Gshape->setLeftBarBgGradient(milestones); - - milestones[1].g = 0.0; milestones[1].b = 1.0; - Bshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_RGBCURVES_BLUE"))); - Bshape->setEditID(EUID_RGB_B, BT_SINGLEPLANE_FLOAT); - Bshape->setBottomBarBgGradient(milestones); - Bshape->setLeftBarBgGradient(milestones); - - // This will add the reset button at the end of the curveType buttons - curveEditorG->curveListComplete(); - - pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4); - -} - -RGBCurves::~RGBCurves () { - delete curveEditorG; -} - -void RGBCurves::read (const ProcParams* pp, const ParamsEdited* pedited) { - - disableListener (); - - if (pedited) { - Rshape->setUnChanged (!pedited->rgbCurves.rcurve); - Gshape->setUnChanged (!pedited->rgbCurves.gcurve); - Bshape->setUnChanged (!pedited->rgbCurves.bcurve); - lumamode->set_inconsistent (!pedited->rgbCurves.lumamode); - } - - lumamodeConn.block (true); - lumamode->set_active (pp->rgbCurves.lumamode); - lumamodeConn.block (false); - - lastLumamode = pp->rgbCurves.lumamode; - - Rshape->setCurve (pp->rgbCurves.rcurve); - Gshape->setCurve (pp->rgbCurves.gcurve); - Bshape->setCurve (pp->rgbCurves.bcurve); - - enableListener (); -} - -void RGBCurves::setEditProvider (EditDataProvider *provider) { - Rshape->setEditProvider(provider); - Gshape->setEditProvider(provider); - Bshape->setEditProvider(provider); -} - -void RGBCurves::autoOpenCurve () { - // Open up the first curve if selected - bool active = Rshape->openIfNonlinear(); - if (!active) Gshape->openIfNonlinear(); - if (!active) Bshape->openIfNonlinear(); -} - -void RGBCurves::write (ProcParams* pp, ParamsEdited* pedited) { - - pp->rgbCurves.rcurve = Rshape->getCurve (); - pp->rgbCurves.gcurve = Gshape->getCurve (); - pp->rgbCurves.bcurve = Bshape->getCurve (); - pp->rgbCurves.lumamode = lumamode->get_active(); - - if (pedited) { - pedited->rgbCurves.rcurve = !Rshape->isUnChanged (); - pedited->rgbCurves.gcurve = !Gshape->isUnChanged (); - pedited->rgbCurves.bcurve = !Bshape->isUnChanged (); - pedited->rgbCurves.lumamode = !lumamode->get_inconsistent(); - } -} - - -/* - * Curve listener - * - * If more than one curve has been added, the curve listener is automatically - * set to 'multi=true', and send a pointer of the modified curve in a parameter - */ -void RGBCurves::curveChanged (CurveEditor* ce) { - - if (listener) { - if (ce == Rshape) - listener->panelChanged (EvRGBrCurve, M("HISTORY_CUSTOMCURVE")); - if (ce == Gshape) - listener->panelChanged (EvRGBgCurve, M("HISTORY_CUSTOMCURVE")); - if (ce == Bshape) - listener->panelChanged (EvRGBbCurve, M("HISTORY_CUSTOMCURVE")); - } -} - -void RGBCurves::lumamodeChanged () { - - if (batchMode) { - if (lumamode->get_inconsistent()) { - lumamode->set_inconsistent (false); - lumamodeConn.block (true); - lumamode->set_active (false); - lumamodeConn.block (false); - } - else if (lastLumamode) - lumamode->set_inconsistent (true); - - lastLumamode = lumamode->get_active (); - } - - if (listener) { - if (lumamode->get_active ()) - listener->panelChanged (EvRGBrCurveLumamode, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvRGBrCurveLumamode, M("GENERAL_DISABLED")); - } -} - -void RGBCurves::setBatchMode (bool batchMode) { - - ToolPanel::setBatchMode (batchMode); - curveEditorG->setBatchMode (batchMode); -} - - -void RGBCurves::updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve, /*LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma) { - - // Rshape->updateBackgroundHistogram (histRed); - // Gshape->updateBackgroundHistogram (histGreen); - // Bshape->updateBackgroundHistogram (histBlue); -} - +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "rgbcurves.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +RGBCurves::RGBCurves () : FoldableToolPanel(this, "rgbcurves", M("TP_RGBCURVES_LABEL")) { + + lumamode = Gtk::manage (new Gtk::CheckButton (M("TP_RGBCURVES_LUMAMODE"))); + lumamode->set_tooltip_markup (M("TP_RGBCURVES_LUMAMODE_TOOLTIP")); + lumamode->set_active (false); + lumamode->show (); + pack_start (*lumamode); + + Gtk::HSeparator *hsep1 = Gtk::manage (new Gtk::HSeparator()); + hsep1->show (); + pack_start (*hsep1); + + lumamodeConn = lumamode->signal_toggled().connect( sigc::mem_fun(*this, &RGBCurves::lumamodeChanged) ); + + std::vector milestones; + + curveEditorG = new CurveEditorGroup (options.lastRgbCurvesDir, M("TP_RGBCURVES_CHANNEL")); + curveEditorG->setCurveListener (this); + + Rshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_RGBCURVES_RED"))); + Rshape->setEditID(EUID_RGB_R, BT_SINGLEPLANE_FLOAT); + milestones.push_back( GradientMilestone(0.0, 0.0, 0.0, 0.0) ); + milestones.push_back( GradientMilestone(1.0, 1.0, 0.0, 0.0) ); + Rshape->setBottomBarBgGradient(milestones); + Rshape->setLeftBarBgGradient(milestones); + + milestones[1].r = 0.0; milestones[1].g = 1.0; + Gshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_RGBCURVES_GREEN"))); + Gshape->setEditID(EUID_RGB_G, BT_SINGLEPLANE_FLOAT); + Gshape->setBottomBarBgGradient(milestones); + Gshape->setLeftBarBgGradient(milestones); + + milestones[1].g = 0.0; milestones[1].b = 1.0; + Bshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_RGBCURVES_BLUE"))); + Bshape->setEditID(EUID_RGB_B, BT_SINGLEPLANE_FLOAT); + Bshape->setBottomBarBgGradient(milestones); + Bshape->setLeftBarBgGradient(milestones); + + // This will add the reset button at the end of the curveType buttons + curveEditorG->curveListComplete(); + + pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4); + +} + +RGBCurves::~RGBCurves () { + delete curveEditorG; +} + +void RGBCurves::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + Rshape->setUnChanged (!pedited->rgbCurves.rcurve); + Gshape->setUnChanged (!pedited->rgbCurves.gcurve); + Bshape->setUnChanged (!pedited->rgbCurves.bcurve); + lumamode->set_inconsistent (!pedited->rgbCurves.lumamode); + } + + lumamodeConn.block (true); + lumamode->set_active (pp->rgbCurves.lumamode); + lumamodeConn.block (false); + + lastLumamode = pp->rgbCurves.lumamode; + + Rshape->setCurve (pp->rgbCurves.rcurve); + Gshape->setCurve (pp->rgbCurves.gcurve); + Bshape->setCurve (pp->rgbCurves.bcurve); + + enableListener (); +} + +void RGBCurves::setEditProvider (EditDataProvider *provider) { + Rshape->setEditProvider(provider); + Gshape->setEditProvider(provider); + Bshape->setEditProvider(provider); +} + +void RGBCurves::autoOpenCurve () { + // Open up the first curve if selected + bool active = Rshape->openIfNonlinear(); + if (!active) Gshape->openIfNonlinear(); + if (!active) Bshape->openIfNonlinear(); +} + +void RGBCurves::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->rgbCurves.rcurve = Rshape->getCurve (); + pp->rgbCurves.gcurve = Gshape->getCurve (); + pp->rgbCurves.bcurve = Bshape->getCurve (); + pp->rgbCurves.lumamode = lumamode->get_active(); + + if (pedited) { + pedited->rgbCurves.rcurve = !Rshape->isUnChanged (); + pedited->rgbCurves.gcurve = !Gshape->isUnChanged (); + pedited->rgbCurves.bcurve = !Bshape->isUnChanged (); + pedited->rgbCurves.lumamode = !lumamode->get_inconsistent(); + } +} + + +/* + * Curve listener + * + * If more than one curve has been added, the curve listener is automatically + * set to 'multi=true', and send a pointer of the modified curve in a parameter + */ +void RGBCurves::curveChanged (CurveEditor* ce) { + + if (listener) { + if (ce == Rshape) + listener->panelChanged (EvRGBrCurve, M("HISTORY_CUSTOMCURVE")); + if (ce == Gshape) + listener->panelChanged (EvRGBgCurve, M("HISTORY_CUSTOMCURVE")); + if (ce == Bshape) + listener->panelChanged (EvRGBbCurve, M("HISTORY_CUSTOMCURVE")); + } +} + +void RGBCurves::lumamodeChanged () { + + if (batchMode) { + if (lumamode->get_inconsistent()) { + lumamode->set_inconsistent (false); + lumamodeConn.block (true); + lumamode->set_active (false); + lumamodeConn.block (false); + } + else if (lastLumamode) + lumamode->set_inconsistent (true); + + lastLumamode = lumamode->get_active (); + } + + if (listener) { + if (lumamode->get_active ()) + listener->panelChanged (EvRGBrCurveLumamode, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvRGBrCurveLumamode, M("GENERAL_DISABLED")); + } +} + +void RGBCurves::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + curveEditorG->setBatchMode (batchMode); +} + + +void RGBCurves::updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve, /*LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma) { + + // Rshape->updateBackgroundHistogram (histRed); + // Gshape->updateBackgroundHistogram (histGreen); + // Bshape->updateBackgroundHistogram (histBlue); +} + diff --git a/rtgui/rtimage.cc b/rtgui/rtimage.cc index 161ee89ec..2211829a0 100644 --- a/rtgui/rtimage.cc +++ b/rtgui/rtimage.cc @@ -1,46 +1,46 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * Copyright (c) 2011 Jean-Christophe FRISCH - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include "rtimage.h" -#include "../rtengine/safegtk.h" - -extern Glib::ustring argv0; -extern Options options; - -std::vector imagesPaths; +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2011 Jean-Christophe FRISCH + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "rtimage.h" +#include "../rtengine/safegtk.h" + +extern Glib::ustring argv0; +extern Options options; + +std::vector imagesPaths; std::map > pixBufMap; // List of image buffers in order to live update them on theme switch and to avoid a lot of file accesses -/* - * RTImage is a derived class of Gtk::Image, in order to handle theme related iconsets - */ +/* + * RTImage is a derived class of Gtk::Image, in order to handle theme related iconsets + */ RTImage::RTImage(Glib::ustring fileName, Glib::ustring rtlFileName) : Gtk::Image() { - Glib::ustring mapKey; - if (rtlFileName.length()) { + Glib::ustring mapKey; + if (rtlFileName.length()) { if (get_direction() == Gtk::TEXT_DIR_RTL) { - mapKey = rtlFileName; + mapKey = rtlFileName; } else { - mapKey = fileName; - } + mapKey = fileName; + } } else { - mapKey = fileName; - } + mapKey = fileName; + } std::map >::iterator it; it = pixBufMap.find(mapKey); @@ -51,18 +51,18 @@ RTImage::RTImage(Glib::ustring fileName, Glib::ustring rtlFileName) : Gtk::Image pixBufMap.insert(std::pair >(mapKey, tempPixPuf)); set(tempPixPuf); } -} - +} + void RTImage::updateImages() { std::map >::iterator it; for (it=pixBufMap.begin(); it!=pixBufMap.end(); ++it) { Glib::ustring fullPath = findIconAbsolutePath(it->first); it->second = Gdk::Pixbuf::create_from_file(fullPath); } -} - -// DONE (was TODO: Maybe this could be optimized: in order to avoid looking up for an icon file in the filesystem on each popupmenu selection, maybe we could find a way to copy the image data from another RTImage) -void RTImage::changeImage(Glib::ustring &newImage) { +} + +// DONE (was TODO: Maybe this could be optimized: in order to avoid looking up for an icon file in the filesystem on each popupmenu selection, maybe we could find a way to copy the image data from another RTImage) +void RTImage::changeImage(Glib::ustring &newImage) { clear(); std::map >::iterator it; it = pixBufMap.find(newImage); @@ -73,77 +73,77 @@ void RTImage::changeImage(Glib::ustring &newImage) { Glib::RefPtr tempPixPuf = Gdk::Pixbuf::create_from_file(fullPath); pixBufMap.insert(std::pair >(newImage, tempPixPuf)); set(tempPixPuf); - } -} - -Glib::ustring RTImage::findIconAbsolutePath(const Glib::ustring &iconFName) { - Glib::ustring path; - for (unsigned int i=0; i - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _RTIMAGE_ -#define _RTIMAGE_ - -#include -#include "options.h" - -class RTImage : public Gtk::Image { -public: - RTImage(Glib::ustring fileName, Glib::ustring rtlFileName = ""); - static void setPaths(Options &opt); - static void updateImages(); - void changeImage(Glib::ustring &newImage); - static Glib::ustring findIconAbsolutePath(const Glib::ustring &iconFName); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _RTIMAGE_ +#define _RTIMAGE_ + +#include +#include "options.h" + +class RTImage : public Gtk::Image { +public: + RTImage(Glib::ustring fileName, Glib::ustring rtlFileName = ""); + static void setPaths(Options &opt); + static void updateImages(); + void changeImage(Glib::ustring &newImage); + static Glib::ustring findIconAbsolutePath(const Glib::ustring &iconFName); +}; + +#endif diff --git a/rtgui/sharpenedge.cc b/rtgui/sharpenedge.cc index dd9ed27b7..e3b3a4e21 100644 --- a/rtgui/sharpenedge.cc +++ b/rtgui/sharpenedge.cc @@ -1,161 +1,161 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "sharpenedge.h" -#include "guiutils.h" -#include "../rtengine/safegtk.h" -#include -#include - -using namespace rtengine; -using namespace rtengine::procparams; - - -SharpenEdge::SharpenEdge () : FoldableToolPanel(this, "sharpenedge", M("TP_SHARPENEDGE_LABEL"), true, true) { - - passes = Gtk::manage(new Adjuster (M("TP_SHARPENEDGE_PASSES"),1,4,1,2)); - passes->setAdjusterListener (this); - if (passes->delay < 1000) passes->delay = 1000; - amount = Gtk::manage(new Adjuster (M("TP_SHARPENEDGE_AMOUNT"),0,100,1,50)); - amount->setAdjusterListener (this); - if (amount->delay < 1000) amount->delay = 1000; - - threechannels = Gtk::manage(new Gtk::CheckButton((M("TP_SHARPENEDGE_THREE"))));// L + a + b - threechannels->set_active (false); - pack_start( *passes, Gtk::PACK_SHRINK, 0);//passes - pack_start( *amount, Gtk::PACK_SHRINK, 0);//amount - pack_start( *threechannels, Gtk::PACK_SHRINK, 0);//one or 3 channels Lab - - show (); - - chanthreeconn = threechannels->signal_toggled().connect( sigc::mem_fun(*this, &SharpenEdge::chanthree_toggled) ); -} - -void SharpenEdge::read(const ProcParams* pp, const ParamsEdited* pedited) { - disableListener (); - - if(pedited ){ - passes->setEditedState (pedited->sharpenEdge.passes ? Edited : UnEdited); - amount->setEditedState (pedited->sharpenEdge.amount ? Edited : UnEdited); - set_inconsistent (multiImage && !pedited->sharpenEdge.enabled); - threechannels->set_inconsistent (!pedited->sharpenEdge.threechannels); - } - - setEnabled(pp->sharpenEdge.enabled); - - chanthreeconn.block (true); - threechannels->set_active (pp->sharpenEdge.threechannels); - chanthreeconn.block (false); - lastchanthree = pp->sharpenEdge.threechannels; - - passes->setValue (pp->sharpenEdge.passes); - amount->setValue (pp->sharpenEdge.amount); - - enableListener (); -} - -void SharpenEdge::write( ProcParams* pp, ParamsEdited* pedited) { - pp->sharpenEdge.enabled = getEnabled(); - pp->sharpenEdge.passes = (int)passes->getValue(); - pp->sharpenEdge.amount = amount->getValue (); - pp->sharpenEdge.threechannels = threechannels->get_active (); - - if (pedited) { - pedited->sharpenEdge.enabled = !get_inconsistent(); - pedited->sharpenEdge.passes = passes->getEditedState (); - pedited->sharpenEdge.amount = amount->getEditedState (); - pedited->sharpenEdge.threechannels = !threechannels->get_inconsistent(); - } - -} - -void SharpenEdge::enabledChanged () { - if (listener) { - if (get_inconsistent()) - listener->panelChanged (EvSharpenEdgeEnabled, M("GENERAL_UNCHANGED")); - else if (getEnabled()) - listener->panelChanged (EvSharpenEdgeEnabled, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvSharpenEdgeEnabled, M("GENERAL_DISABLED")); - } -} - -void SharpenEdge::chanthree_toggled () { - - if (batchMode) { - if (threechannels->get_inconsistent()) { - threechannels->set_inconsistent (false); - chanthreeconn.block (true); - threechannels->set_active (false); - chanthreeconn.block (false); - } - else if (lastchanthree) - threechannels->set_inconsistent (true); - - lastchanthree = threechannels->get_active (); - } - - if (listener && getEnabled()) { - if (threechannels->get_active ()) - listener->panelChanged (EvSharpenEdgeThreechannels, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvSharpenEdgeThreechannels, M("GENERAL_DISABLED")); - } -} - -void SharpenEdge::adjusterChanged (Adjuster* a, double newval) { - if (listener && getEnabled()) { - Glib::ustring value = a->getTextValue(); - - if (a == passes ) - listener->panelChanged (EvSharpenEdgePasses, value ); - else if (a == amount) - listener->panelChanged (EvSharpenEdgeAmount, value ); - } -} - -void SharpenEdge::setBatchMode(bool batchMode) { - passes->showEditedCB (); - amount->showEditedCB (); -} - -void SharpenEdge::setDefaults(const ProcParams* defParams, const ParamsEdited* pedited) { - passes->setDefault (defParams->sharpenEdge.passes); - amount->setDefault (defParams->sharpenEdge.amount); - - if (pedited) { - passes->setDefaultEditedState (pedited->sharpenEdge.passes ? Edited : UnEdited); - amount->setDefaultEditedState (pedited->sharpenEdge.amount ? Edited : UnEdited); - - } else { - passes->setDefaultEditedState (Irrelevant); - amount->setDefaultEditedState (Irrelevant); - - } -} - -void SharpenEdge::setAdjusterBehavior (bool amountadd, bool passadd) { - amount->setAddMode (amountadd); - passes->setAddMode (passadd); -} - -void SharpenEdge::trimValues (ProcParams* pp) { - amount->trimValue (pp->sharpenEdge.amount); - passes->trimValue (pp->sharpenEdge.passes); - -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "sharpenedge.h" +#include "guiutils.h" +#include "../rtengine/safegtk.h" +#include +#include + +using namespace rtengine; +using namespace rtengine::procparams; + + +SharpenEdge::SharpenEdge () : FoldableToolPanel(this, "sharpenedge", M("TP_SHARPENEDGE_LABEL"), true, true) { + + passes = Gtk::manage(new Adjuster (M("TP_SHARPENEDGE_PASSES"),1,4,1,2)); + passes->setAdjusterListener (this); + if (passes->delay < 1000) passes->delay = 1000; + amount = Gtk::manage(new Adjuster (M("TP_SHARPENEDGE_AMOUNT"),0,100,1,50)); + amount->setAdjusterListener (this); + if (amount->delay < 1000) amount->delay = 1000; + + threechannels = Gtk::manage(new Gtk::CheckButton((M("TP_SHARPENEDGE_THREE"))));// L + a + b + threechannels->set_active (false); + pack_start( *passes, Gtk::PACK_SHRINK, 0);//passes + pack_start( *amount, Gtk::PACK_SHRINK, 0);//amount + pack_start( *threechannels, Gtk::PACK_SHRINK, 0);//one or 3 channels Lab + + show (); + + chanthreeconn = threechannels->signal_toggled().connect( sigc::mem_fun(*this, &SharpenEdge::chanthree_toggled) ); +} + +void SharpenEdge::read(const ProcParams* pp, const ParamsEdited* pedited) { + disableListener (); + + if(pedited ){ + passes->setEditedState (pedited->sharpenEdge.passes ? Edited : UnEdited); + amount->setEditedState (pedited->sharpenEdge.amount ? Edited : UnEdited); + set_inconsistent (multiImage && !pedited->sharpenEdge.enabled); + threechannels->set_inconsistent (!pedited->sharpenEdge.threechannels); + } + + setEnabled(pp->sharpenEdge.enabled); + + chanthreeconn.block (true); + threechannels->set_active (pp->sharpenEdge.threechannels); + chanthreeconn.block (false); + lastchanthree = pp->sharpenEdge.threechannels; + + passes->setValue (pp->sharpenEdge.passes); + amount->setValue (pp->sharpenEdge.amount); + + enableListener (); +} + +void SharpenEdge::write( ProcParams* pp, ParamsEdited* pedited) { + pp->sharpenEdge.enabled = getEnabled(); + pp->sharpenEdge.passes = (int)passes->getValue(); + pp->sharpenEdge.amount = amount->getValue (); + pp->sharpenEdge.threechannels = threechannels->get_active (); + + if (pedited) { + pedited->sharpenEdge.enabled = !get_inconsistent(); + pedited->sharpenEdge.passes = passes->getEditedState (); + pedited->sharpenEdge.amount = amount->getEditedState (); + pedited->sharpenEdge.threechannels = !threechannels->get_inconsistent(); + } + +} + +void SharpenEdge::enabledChanged () { + if (listener) { + if (get_inconsistent()) + listener->panelChanged (EvSharpenEdgeEnabled, M("GENERAL_UNCHANGED")); + else if (getEnabled()) + listener->panelChanged (EvSharpenEdgeEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvSharpenEdgeEnabled, M("GENERAL_DISABLED")); + } +} + +void SharpenEdge::chanthree_toggled () { + + if (batchMode) { + if (threechannels->get_inconsistent()) { + threechannels->set_inconsistent (false); + chanthreeconn.block (true); + threechannels->set_active (false); + chanthreeconn.block (false); + } + else if (lastchanthree) + threechannels->set_inconsistent (true); + + lastchanthree = threechannels->get_active (); + } + + if (listener && getEnabled()) { + if (threechannels->get_active ()) + listener->panelChanged (EvSharpenEdgeThreechannels, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvSharpenEdgeThreechannels, M("GENERAL_DISABLED")); + } +} + +void SharpenEdge::adjusterChanged (Adjuster* a, double newval) { + if (listener && getEnabled()) { + Glib::ustring value = a->getTextValue(); + + if (a == passes ) + listener->panelChanged (EvSharpenEdgePasses, value ); + else if (a == amount) + listener->panelChanged (EvSharpenEdgeAmount, value ); + } +} + +void SharpenEdge::setBatchMode(bool batchMode) { + passes->showEditedCB (); + amount->showEditedCB (); +} + +void SharpenEdge::setDefaults(const ProcParams* defParams, const ParamsEdited* pedited) { + passes->setDefault (defParams->sharpenEdge.passes); + amount->setDefault (defParams->sharpenEdge.amount); + + if (pedited) { + passes->setDefaultEditedState (pedited->sharpenEdge.passes ? Edited : UnEdited); + amount->setDefaultEditedState (pedited->sharpenEdge.amount ? Edited : UnEdited); + + } else { + passes->setDefaultEditedState (Irrelevant); + amount->setDefaultEditedState (Irrelevant); + + } +} + +void SharpenEdge::setAdjusterBehavior (bool amountadd, bool passadd) { + amount->setAddMode (amountadd); + passes->setAddMode (passadd); +} + +void SharpenEdge::trimValues (ProcParams* pp) { + amount->trimValue (pp->sharpenEdge.amount); + passes->trimValue (pp->sharpenEdge.passes); + +} diff --git a/rtgui/sharpenmicro.cc b/rtgui/sharpenmicro.cc index 3577ba217..5fe7b2af0 100644 --- a/rtgui/sharpenmicro.cc +++ b/rtgui/sharpenmicro.cc @@ -1,162 +1,162 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "sharpenmicro.h" -#include "guiutils.h" -#include "../rtengine/safegtk.h" -#include -#include - -using namespace rtengine; -using namespace rtengine::procparams; - - -SharpenMicro::SharpenMicro () : FoldableToolPanel(this, "sharpenmicro", M("TP_SHARPENMICRO_LABEL"), true, true) { - - setEnabledTooltipMarkup(M("TP_SHARPENING_TOOLTIP")); - - amount= Gtk::manage(new Adjuster (M("TP_SHARPENMICRO_AMOUNT"),0,100,1,20)); - amount->setAdjusterListener (this); - if (amount->delay < 1000) amount->delay = 1000; - amount->show(); - uniformity= Gtk::manage(new Adjuster (M("TP_SHARPENMICRO_UNIFORMITY"),0,100,10,50)); - - uniformity->setAdjusterListener (this); - if (uniformity->delay < 1000) uniformity->delay = 1000; - uniformity->show(); - matrix = Gtk::manage (new Gtk::CheckButton (M("TP_SHARPENMICRO_MATRIX"))); - matrix->set_active (true); - pack_start(*matrix, Gtk::PACK_SHRINK, 0); - matrix->show (); - - pack_start( *amount, Gtk::PACK_SHRINK, 0); - pack_start( *uniformity, Gtk::PACK_SHRINK, 0); - - show (); - - matrixconn = matrix->signal_toggled().connect( sigc::mem_fun(*this, &SharpenMicro::matrix_toggled) ); -} - -void SharpenMicro::read(const ProcParams* pp, const ParamsEdited* pedited) { - disableListener (); - - if(pedited ){ - set_inconsistent (multiImage && !pedited->sharpenMicro.enabled); - matrix->set_inconsistent (!pedited->sharpenMicro.matrix); - amount->setEditedState (pedited->sharpenMicro.amount ? Edited : UnEdited); - uniformity->setEditedState (pedited->sharpenMicro.uniformity ? Edited : UnEdited); - } - - setEnabled(pp->sharpenMicro.enabled); - - matrixconn.block (true); - matrix->set_active (pp->sharpenMicro.matrix); - matrixconn.block (false); - lastmatrix = pp->sharpenMicro.matrix; - - amount->setValue (pp->sharpenMicro.amount); - uniformity->setValue (pp->sharpenMicro.uniformity); - - enableListener (); -} - -void SharpenMicro::write( ProcParams* pp, ParamsEdited* pedited) { - pp->sharpenMicro.enabled = getEnabled(); - pp->sharpenMicro.matrix = matrix->get_active (); - pp->sharpenMicro.amount = amount->getValue (); - pp->sharpenMicro.uniformity = uniformity->getValue (); - - if (pedited) { - pedited->sharpenMicro.enabled = !get_inconsistent(); - pedited->sharpenMicro.matrix = !matrix->get_inconsistent(); - pedited->sharpenMicro.amount = amount->getEditedState (); - pedited->sharpenMicro.uniformity = uniformity->getEditedState (); - } -} - -void SharpenMicro::enabledChanged () { - - if (listener) { - if (get_inconsistent()) - listener->panelChanged (EvSharpenMicroEnabled, M("GENERAL_UNCHANGED")); - else if (getEnabled()) - listener->panelChanged (EvSharpenMicroEnabled, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvSharpenMicroEnabled, M("GENERAL_DISABLED")); - } -} - -void SharpenMicro::matrix_toggled () { - if (batchMode) { - if (matrix->get_inconsistent()) { - matrix->set_inconsistent (false); - matrixconn.block (true); - matrix->set_active (false); - matrixconn.block (false); - } - else if (lastmatrix) - matrix->set_inconsistent (true); - - lastmatrix = matrix->get_active (); - } - - if (listener && getEnabled()) { - if (matrix->get_active ()) - listener->panelChanged (EvSharpenMicroMatrix, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvSharpenMicroMatrix, M("GENERAL_DISABLED")); - } -} - -void SharpenMicro::adjusterChanged (Adjuster* a, double newval) { - if (listener && getEnabled()) { - Glib::ustring value = a->getTextValue(); - if (a == amount) - listener->panelChanged (EvSharpenMicroAmount, value ); - else if (a == uniformity) - listener->panelChanged (EvSharpenMicroUniformity, value ); - } -} - -void SharpenMicro::setBatchMode(bool batchMode) { - amount->showEditedCB (); - uniformity->showEditedCB (); -} - -void SharpenMicro::setDefaults(const ProcParams* defParams, const ParamsEdited* pedited) { - amount->setDefault (defParams->sharpenMicro.amount); - uniformity->setDefault (defParams->sharpenMicro.uniformity); - - if (pedited) { - amount->setDefaultEditedState (pedited->sharpenMicro.amount ? Edited : UnEdited); - uniformity->setDefaultEditedState (pedited->sharpenMicro.uniformity ? Edited : UnEdited); - } else { - amount->setDefaultEditedState (Irrelevant); - uniformity->setDefaultEditedState (Irrelevant); - } -} - -void SharpenMicro::setAdjusterBehavior (bool amountadd, bool uniformityadd ) { - amount->setAddMode (amountadd); - uniformity->setAddMode (uniformityadd); -} - -void SharpenMicro::trimValues (ProcParams* pp) { - amount->trimValue (pp->sharpenMicro.amount); - uniformity->trimValue (pp->sharpenMicro.uniformity); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "sharpenmicro.h" +#include "guiutils.h" +#include "../rtengine/safegtk.h" +#include +#include + +using namespace rtengine; +using namespace rtengine::procparams; + + +SharpenMicro::SharpenMicro () : FoldableToolPanel(this, "sharpenmicro", M("TP_SHARPENMICRO_LABEL"), true, true) { + + setEnabledTooltipMarkup(M("TP_SHARPENING_TOOLTIP")); + + amount= Gtk::manage(new Adjuster (M("TP_SHARPENMICRO_AMOUNT"),0,100,1,20)); + amount->setAdjusterListener (this); + if (amount->delay < 1000) amount->delay = 1000; + amount->show(); + uniformity= Gtk::manage(new Adjuster (M("TP_SHARPENMICRO_UNIFORMITY"),0,100,10,50)); + + uniformity->setAdjusterListener (this); + if (uniformity->delay < 1000) uniformity->delay = 1000; + uniformity->show(); + matrix = Gtk::manage (new Gtk::CheckButton (M("TP_SHARPENMICRO_MATRIX"))); + matrix->set_active (true); + pack_start(*matrix, Gtk::PACK_SHRINK, 0); + matrix->show (); + + pack_start( *amount, Gtk::PACK_SHRINK, 0); + pack_start( *uniformity, Gtk::PACK_SHRINK, 0); + + show (); + + matrixconn = matrix->signal_toggled().connect( sigc::mem_fun(*this, &SharpenMicro::matrix_toggled) ); +} + +void SharpenMicro::read(const ProcParams* pp, const ParamsEdited* pedited) { + disableListener (); + + if(pedited ){ + set_inconsistent (multiImage && !pedited->sharpenMicro.enabled); + matrix->set_inconsistent (!pedited->sharpenMicro.matrix); + amount->setEditedState (pedited->sharpenMicro.amount ? Edited : UnEdited); + uniformity->setEditedState (pedited->sharpenMicro.uniformity ? Edited : UnEdited); + } + + setEnabled(pp->sharpenMicro.enabled); + + matrixconn.block (true); + matrix->set_active (pp->sharpenMicro.matrix); + matrixconn.block (false); + lastmatrix = pp->sharpenMicro.matrix; + + amount->setValue (pp->sharpenMicro.amount); + uniformity->setValue (pp->sharpenMicro.uniformity); + + enableListener (); +} + +void SharpenMicro::write( ProcParams* pp, ParamsEdited* pedited) { + pp->sharpenMicro.enabled = getEnabled(); + pp->sharpenMicro.matrix = matrix->get_active (); + pp->sharpenMicro.amount = amount->getValue (); + pp->sharpenMicro.uniformity = uniformity->getValue (); + + if (pedited) { + pedited->sharpenMicro.enabled = !get_inconsistent(); + pedited->sharpenMicro.matrix = !matrix->get_inconsistent(); + pedited->sharpenMicro.amount = amount->getEditedState (); + pedited->sharpenMicro.uniformity = uniformity->getEditedState (); + } +} + +void SharpenMicro::enabledChanged () { + + if (listener) { + if (get_inconsistent()) + listener->panelChanged (EvSharpenMicroEnabled, M("GENERAL_UNCHANGED")); + else if (getEnabled()) + listener->panelChanged (EvSharpenMicroEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvSharpenMicroEnabled, M("GENERAL_DISABLED")); + } +} + +void SharpenMicro::matrix_toggled () { + if (batchMode) { + if (matrix->get_inconsistent()) { + matrix->set_inconsistent (false); + matrixconn.block (true); + matrix->set_active (false); + matrixconn.block (false); + } + else if (lastmatrix) + matrix->set_inconsistent (true); + + lastmatrix = matrix->get_active (); + } + + if (listener && getEnabled()) { + if (matrix->get_active ()) + listener->panelChanged (EvSharpenMicroMatrix, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvSharpenMicroMatrix, M("GENERAL_DISABLED")); + } +} + +void SharpenMicro::adjusterChanged (Adjuster* a, double newval) { + if (listener && getEnabled()) { + Glib::ustring value = a->getTextValue(); + if (a == amount) + listener->panelChanged (EvSharpenMicroAmount, value ); + else if (a == uniformity) + listener->panelChanged (EvSharpenMicroUniformity, value ); + } +} + +void SharpenMicro::setBatchMode(bool batchMode) { + amount->showEditedCB (); + uniformity->showEditedCB (); +} + +void SharpenMicro::setDefaults(const ProcParams* defParams, const ParamsEdited* pedited) { + amount->setDefault (defParams->sharpenMicro.amount); + uniformity->setDefault (defParams->sharpenMicro.uniformity); + + if (pedited) { + amount->setDefaultEditedState (pedited->sharpenMicro.amount ? Edited : UnEdited); + uniformity->setDefaultEditedState (pedited->sharpenMicro.uniformity ? Edited : UnEdited); + } else { + amount->setDefaultEditedState (Irrelevant); + uniformity->setDefaultEditedState (Irrelevant); + } +} + +void SharpenMicro::setAdjusterBehavior (bool amountadd, bool uniformityadd ) { + amount->setAddMode (amountadd); + uniformity->setAddMode (uniformityadd); +} + +void SharpenMicro::trimValues (ProcParams* pp) { + amount->trimValue (pp->sharpenMicro.amount); + uniformity->trimValue (pp->sharpenMicro.uniformity); +} diff --git a/rtgui/soundman.cc b/rtgui/soundman.cc index 07ff9986d..9cb3450dc 100644 --- a/rtgui/soundman.cc +++ b/rtgui/soundman.cc @@ -1,71 +1,71 @@ -/* -* This file is part of RawTherapee. -* -* Copyright (c) 2010 Oliver Duis -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -* -*/ - -#include "soundman.h" -#include "options.h" - -#ifdef WIN32 -#include -#include -#endif - -#ifdef __linux__ -#include -#endif - - -void SoundManager::init() -{ -#ifdef WIN32 -// TODO: On Windows Vista/7 RT should register with the OS sound system, so it can enjoy application specific -// volume, safed, process independent etc. from the start. -// Function call is IAudioClient::Initialize -// Unfortunately MinGW does not support this yet. If audioclient.h is available, add an Init -// called once on program start. - // - // This mitigation plays an empty file on start, so RT is immidiately avaible in the Windows mixer at least - playSoundAsync(Glib::ustring("sounds\\Empty.wav")); -#endif -} - -// Plays a sound in async mode to not block the main thread -// param is either file name or name of the system event on Windows (e.g. "SystemAsterisk" or "SystemDefault"). -void SoundManager::playSoundAsync(const Glib::ustring &sound) -{ - if (sound.empty() || !options.sndEnable) return; - -#ifdef WIN32 - DWORD sndParam=SND_ASYNC | SND_NODEFAULT; - - if (sound.find('.')!=Glib::ustring::npos) { - // contain dot, so it's a filename - sndParam|=SND_FILENAME; - } else { - // no dot, so it's a system event - sndParam|=SND_ALIAS; - } - - wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (sound.c_str(), -1, NULL, NULL, NULL); - PlaySoundW(wfilename, NULL, sndParam); - g_free( wfilename ); -#elif defined(__linux__) - ca_context_play(ca_gtk_context_get(), 0, CA_PROP_EVENT_ID, sound.c_str(), CA_PROP_MEDIA_FILENAME, sound.c_str(), NULL); -#endif -} +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2010 Oliver Duis +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +* +*/ + +#include "soundman.h" +#include "options.h" + +#ifdef WIN32 +#include +#include +#endif + +#ifdef __linux__ +#include +#endif + + +void SoundManager::init() +{ +#ifdef WIN32 +// TODO: On Windows Vista/7 RT should register with the OS sound system, so it can enjoy application specific +// volume, safed, process independent etc. from the start. +// Function call is IAudioClient::Initialize +// Unfortunately MinGW does not support this yet. If audioclient.h is available, add an Init +// called once on program start. + // + // This mitigation plays an empty file on start, so RT is immidiately avaible in the Windows mixer at least + playSoundAsync(Glib::ustring("sounds\\Empty.wav")); +#endif +} + +// Plays a sound in async mode to not block the main thread +// param is either file name or name of the system event on Windows (e.g. "SystemAsterisk" or "SystemDefault"). +void SoundManager::playSoundAsync(const Glib::ustring &sound) +{ + if (sound.empty() || !options.sndEnable) return; + +#ifdef WIN32 + DWORD sndParam=SND_ASYNC | SND_NODEFAULT; + + if (sound.find('.')!=Glib::ustring::npos) { + // contain dot, so it's a filename + sndParam|=SND_FILENAME; + } else { + // no dot, so it's a system event + sndParam|=SND_ALIAS; + } + + wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (sound.c_str(), -1, NULL, NULL, NULL); + PlaySoundW(wfilename, NULL, sndParam); + g_free( wfilename ); +#elif defined(__linux__) + ca_context_play(ca_gtk_context_get(), 0, CA_PROP_EVENT_ID, sound.c_str(), CA_PROP_MEDIA_FILENAME, sound.c_str(), NULL); +#endif +} diff --git a/rtgui/soundman.h b/rtgui/soundman.h index d4cb48b33..d6d39314f 100644 --- a/rtgui/soundman.h +++ b/rtgui/soundman.h @@ -1,32 +1,32 @@ -/* -* This file is part of RawTherapee. -* -* Copyright (c) 2010 Oliver Duis -* -* RawTherapee is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* RawTherapee is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with RawTherapee. If not, see . -* -*/ - -#ifndef _SOUNDMAN_ -#define _SOUNDMAN_ - -#include "../rtengine/safegtk.h" - -class SoundManager { -public: - static void init(); - static void playSoundAsync(const Glib::ustring &sound); -}; - -#endif +/* +* This file is part of RawTherapee. +* +* Copyright (c) 2010 Oliver Duis +* +* RawTherapee is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* RawTherapee is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with RawTherapee. If not, see . +* +*/ + +#ifndef _SOUNDMAN_ +#define _SOUNDMAN_ + +#include "../rtengine/safegtk.h" + +class SoundManager { +public: + static void init(); + static void playSoundAsync(const Glib::ustring &sound); +}; + +#endif diff --git a/rtgui/thumbbrowserbase.cc b/rtgui/thumbbrowserbase.cc index ceb566b22..8499ba668 100644 --- a/rtgui/thumbbrowserbase.cc +++ b/rtgui/thumbbrowserbase.cc @@ -1,1026 +1,1026 @@ -/* - * This file is part of RawTherapee. - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include -#include "../rtengine/rt_math.h" - -#include "thumbbrowserbase.h" -#include "multilangmgr.h" -#include "options.h" -#include "../rtengine/mytime.h" - -using namespace std; - -ThumbBrowserBase::ThumbBrowserBase () - : lastClicked(NULL), previewHeight(options.thumbSize), numOfCols(1), inspector(NULL), isInspectorActive(false) { - location = THLOC_FILEBROWSER; - inW = -1; inH = -1; - - Gtk::HBox* hb1 = Gtk::manage( new Gtk::HBox () ); - Gtk::HBox* hb2 = Gtk::manage( new Gtk::HBox () ); - Gtk::Frame* frame = Gtk::manage( new Gtk::Frame () ); - frame->add (internal); - frame->set_shadow_type (Gtk::SHADOW_IN ); - hb1->pack_start (*frame); - hb1->pack_end (vscroll, Gtk::PACK_SHRINK, 0); - - pack_start (*hb1); - - hb2->pack_start (hscroll); - - pack_start (*hb2,Gtk::PACK_SHRINK, 0); - - internal.setParent (this); - - show_all (); - - hscroll.set_update_policy (Gtk::UPDATE_CONTINUOUS); - vscroll.set_update_policy (Gtk::UPDATE_CONTINUOUS); - - vscroll.signal_value_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::scrollChanged) ); - hscroll.signal_value_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::scrollChanged) ); - - internal.signal_size_allocate().connect( sigc::mem_fun(*this, &ThumbBrowserBase::internalAreaResized) ); -} - -void ThumbBrowserBase::scrollChanged () { - { - #if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); - #endif - - for (size_t i=0; isetOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); - } - - internal.setPosition ((int)(hscroll.get_value()), (int)(vscroll.get_value())); - - if (!internal.isDirty()) { - internal.setDirty (); - internal.queue_draw (); - } -} - -void ThumbBrowserBase::scroll (int direction) { - // GUI already acquired when here - if (arrangement==TB_Vertical) - vscroll.set_value (vscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * vscroll.get_adjustment()->get_step_increment()); - else - hscroll.set_value (hscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * hscroll.get_adjustment()->get_step_increment()); -} - -void ThumbBrowserBase::scrollPage (int direction) { - // GUI already acquired when here - if (arrangement==TB_Vertical) - vscroll.set_value (vscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * vscroll.get_adjustment()->get_page_increment()); - else - hscroll.set_value (hscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * hscroll.get_adjustment()->get_page_increment()); -} - -static void scrollToEntry (double& h, double& v, int iw, int ih, ThumbBrowserEntryBase* entry) { - const int hmin = entry->getX (); - const int hmax = hmin + entry->getEffectiveWidth () - iw; - const int vmin = entry->getY (); - const int vmax = vmin + entry->getEffectiveHeight () - ih; - - if (hmin < 0) - h += hmin; - else if (hmax > 0) - h += hmax; - - if(vmin < 0) - v += vmin; - else if (vmax > 0) - v += vmax; -} - -void ThumbBrowserBase::selectPrev (int distance, bool enlarge) { - double h, v; - getScrollPosition (h, v); - - { - #if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); - #endif - - if (!selected.empty ()) { - std::vector::iterator front = std::find (fd.begin (), fd.end (), selected.front ()); - std::vector::iterator back = std::find (fd.begin (), fd.end (), selected.back ()); - std::vector::iterator last = std::find (fd.begin (), fd.end (), lastClicked); - - if (front > back) - std::swap(front, back); - - std::vector::iterator& curr = last == front ? front : back; - - // find next thumbnail at filtered distance before current - for (; curr >= fd.begin (); --curr) { - if (!(*curr)->filtered) { - if (distance-- == 0) { - // clear current selection - for (size_t i=0; iselected = false; - redrawNeeded (selected[i]); - } - selected.clear (); - - // make sure the newly selected thumbnail is visible and make it current - scrollToEntry (h, v, internal.get_width (), internal.get_height (), *curr); - lastClicked = *curr; - - // either enlarge current selection or set new selection - if(enlarge) { - // reverse direction if distance is too large - if(front > back) - std::swap(front, back); - - for (; front <= back; ++front) { - if (!(*front)->filtered) { - (*front)->selected = true; - redrawNeeded (*front); - selected.push_back (*front); - } - } - } - else { - (*curr)->selected = true; - redrawNeeded (*curr); - selected.push_back (*curr); - } - - break; - } - } - } - } - - #if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); - #endif - selectionChanged (); - } - - setScrollPosition (h, v); -} - -void ThumbBrowserBase::selectNext (int distance, bool enlarge) { - double h, v; - getScrollPosition (h, v); - - { - #if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); - #endif - - if (!selected.empty ()) { - std::vector::iterator front = std::find (fd.begin (), fd.end (), selected.front ()); - std::vector::iterator back = std::find (fd.begin (), fd.end (), selected.back ()); - std::vector::iterator last = std::find (fd.begin (), fd.end (), lastClicked); - - if (front > back) - std::swap(front, back); - - std::vector::iterator& curr = last == back ? back : front; - - // find next thumbnail at filtered distance after current - for (; curr < fd.end (); ++curr) { - if (!(*curr)->filtered) { - if (distance-- == 0) { - // clear current selection - for (size_t i=0; iselected = false; - redrawNeeded (selected[i]); - } - selected.clear (); - - // make sure the newly selected thumbnail is visible and make it current - scrollToEntry (h, v, internal.get_width (), internal.get_height (), *curr); - lastClicked = *curr; - - // either enlarge current selection or set new selection - if(enlarge) { - // reverse direction if distance is too large - if(front > back) - std::swap(front, back); - - for (; front <= back; ++front) { - if (!(*front)->filtered) { - (*front)->selected = true; - redrawNeeded (*front); - selected.push_back (*front); - } - } - } - else { - (*curr)->selected = true; - redrawNeeded (*curr); - selected.push_back (*curr); - } - - break; - } - } - } - } - - #if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); - #endif - selectionChanged (); - } - - setScrollPosition (h, v); -} - -void ThumbBrowserBase::selectFirst (bool enlarge) { - double h, v; - getScrollPosition (h, v); - - { - #if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); - #endif - - if (!fd.empty ()) { - // find first unfiltered entry - std::vector::iterator first = fd.begin (); - - for (; first < fd.end (); ++first) { - if (!(*first)->filtered) { - break; - } - } - - scrollToEntry (h, v, internal.get_width (), internal.get_height (), *first); - - ThumbBrowserEntryBase* lastEntry = lastClicked; - lastClicked = *first; - - if(selected.empty ()) { - (*first)->selected = true; - redrawNeeded (*first); - selected.push_back (*first); - } - else { - std::vector::iterator back = std::find (fd.begin (), fd.end (), lastEntry ? lastEntry : selected.back ()); - - if (first > back) - std::swap(first, back); - - // clear current selection - for (size_t i=0; iselected = false; - redrawNeeded (selected[i]); - } - selected.clear (); - - // either enlarge current selection or set new selection - for (; first <= back; ++first) { - if (!(*first)->filtered) { - (*first)->selected = true; - redrawNeeded (*first); - selected.push_back (*first); - } - - if (!enlarge) - break; - } - } - } - - #if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); - #endif - selectionChanged (); - } - - setScrollPosition (h, v); -} - -void ThumbBrowserBase::selectLast (bool enlarge) { - double h, v; - getScrollPosition (h, v); - - { - #if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); - #endif - - if (!fd.empty ()) { - // find last unfiltered entry - std::vector::iterator last = fd.end () - 1; - - for (; last >= fd.begin (); --last) { - if (!(*last)->filtered) { - break; - } - } - - scrollToEntry (h, v, internal.get_width (), internal.get_height (), *last); - - ThumbBrowserEntryBase* lastEntry = lastClicked; - lastClicked = *last; - - if(selected.empty()) { - (*last)->selected = true; - redrawNeeded (*last); - selected.push_back (*last); - } - else { - std::vector::iterator front = std::find (fd.begin (), fd.end (), lastEntry ? lastEntry : selected.front ()); - - if (last < front) - std::swap(last, front); - - // clear current selection - for (size_t i=0; iselected = false; - redrawNeeded (selected[i]); - } - selected.clear (); - - // either enlarge current selection or set new selection - for (; front <= last; --last) { - if (!(*last)->filtered) { - (*last)->selected = true; - redrawNeeded (*last); - selected.push_back (*last); - } - - if (!enlarge) - break; - } - - std::reverse(selected.begin (), selected.end ()); - } - } - - #if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); - #endif - selectionChanged (); - } - - setScrollPosition (h, v); -} - -void ThumbBrowserBase::resizeThumbnailArea (int w, int h) { - - inW = w; - inH = h; - - if (hscroll.get_value() + internal.get_width() > inW) - hscroll.set_value (inW - internal.get_width()); - if (vscroll.get_value() + internal.get_height() > inH) - vscroll.set_value (inH - internal.get_height()); - - configScrollBars (); -} - -void ThumbBrowserBase::internalAreaResized (Gtk::Allocation& req) { - - if (inW>0 && inH>0) { - configScrollBars (); - redraw (); - } -} - -void ThumbBrowserBase::configScrollBars () { - - // HOMBRE:DELETE ME? - GThreadLock tLock; // Acquire the GUI - - if (inW>0 && inH>0) { - - int iw = internal.get_width (); - int ih = internal.get_height (); - - hscroll.get_adjustment()->set_upper (inW); - vscroll.get_adjustment()->set_upper (inH); - hscroll.get_adjustment()->set_lower (0); - vscroll.get_adjustment()->set_lower (0); - hscroll.get_adjustment()->set_step_increment (32); - vscroll.get_adjustment()->set_step_increment (32); - hscroll.get_adjustment()->set_page_increment (iw); - vscroll.get_adjustment()->set_page_increment (ih); - hscroll.get_adjustment()->set_page_size (iw); - vscroll.get_adjustment()->set_page_size (ih); - - if(iw>=inW) - hscroll.hide(); - else - hscroll.show(); - - if(ih>=inH) - vscroll.hide(); - else - vscroll.show(); - } -} - -void ThumbBrowserBase::arrangeFiles () { - - #if PROTECT_VECTORS - MYREADERLOCK(l, entryRW); - #endif - - // GUI already locked by ::redraw, the only caller of this method for now. - // We could lock it one more time, there's no harm excepted (negligible) speed penalty - //GThreadLock lock; - - int N = fd.size (); - // apply filter - for (int i=0; ifiltered = !checkFilter (fd[i]); - - int rowHeight = 0; - // compute size of the items - for (int i=0; ifiltered && fd[i]->getMinimalHeight() > rowHeight) - rowHeight = fd[i]->getMinimalHeight (); - - if (arrangement==TB_Horizontal) { - numOfCols = 1; - int numOfRows = 1; -// if (rowHeight>0) { -// numOfRows = (internal.get_height()+rowHeight/2)/rowHeight; -// if (numOfRows<1) -// numOfRows = 1; -// } - - int ct = 0; - int currx = 0; int curry = 0; - while (ctgetMinimalWidth() > maxw) - maxw = fd[ct+i]->getMinimalWidth (); - - // arrange items in the column - curry = 0; - for (int i=0; ctfiltered) - fd[ct++]->drawable = false; - if (ctsetPosition (currx, curry, maxw, rowHeight); - fd[ct]->drawable = true; - curry += rowHeight; - } - } - currx += maxw; - } - #if PROTECT_VECTORS - MYREADERLOCK_RELEASE(l); - #endif - // This will require a Writer access - resizeThumbnailArea (currx, numOfRows*rowHeight); - } - else { - int availWidth = internal.get_width(); - // initial number of columns - numOfCols = 0; - int colsWidth = 0; - for (int i=0; ifiltered && colsWidth + fd[i]->getMinimalWidth() <= availWidth) { - colsWidth += fd[numOfCols]->getMinimalWidth (); - numOfCols++; - } - if (numOfCols<1) - numOfCols = 1; - std::vector colWidths; - for (; numOfCols>0; numOfCols--) { - // compute column widths - colWidths.resize (numOfCols); - for (int i=0; ifiltered && fd[i]->getMinimalWidth() > colWidths[j%numOfCols]) - colWidths[j%numOfCols] = fd[i]->getMinimalWidth (); - if (!fd[i]->filtered) - j++; - } - // if not wider than the space available, arrange it and we are ready - colsWidth = 0; - for (int i=0; ifiltered) - fd[ct++]->drawable = false; - if (ctsetPosition (currx, curry, colWidths[i%numOfCols], rowHeight); - fd[ct]->drawable = true; - currx += colWidths[i%numOfCols]; - } - } - if (currx>0) // there were thumbnails placed in the row - curry += rowHeight; - } - #if PROTECT_VECTORS - MYREADERLOCK_RELEASE(l); - #endif - // This will require a Writer access - resizeThumbnailArea (colsWidth, curry); - } -} - -void ThumbBrowserBase::disableInspector() { - if (inspector) - inspector->setActive(false); -} - -void ThumbBrowserBase::enableInspector() { - if (inspector) - inspector->setActive(true); -} - -void ThumbBrowserBase::Internal::on_realize() { - // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) - Cairo::FontOptions cfo; - cfo.set_antialias (Cairo::ANTIALIAS_SUBPIXEL); - get_pango_context()->set_cairo_font_options (cfo); - - Gtk::DrawingArea::on_realize(); - Glib::RefPtr window = get_window(); - set_flags (Gtk::CAN_FOCUS); - add_events(Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK); - gc_ = Gdk::GC::create(window); - set_has_tooltip (true); - signal_query_tooltip().connect( sigc::mem_fun(*this, &ThumbBrowserBase::Internal::on_query_tooltip) ); -} - -bool ThumbBrowserBase::Internal::on_query_tooltip (int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) { - // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) - Glib::ustring ttip = ""; - - { - #if PROTECT_VECTORS - MYREADERLOCK(l, parent->entryRW); - #endif - - for (size_t i=0; ifd.size(); i++) - if (parent->fd[i]->drawable && parent->fd[i]->inside (x, y)) { - ttip = parent->fd[i]->getToolTip (x, y); - break; - } - } - if (ttip!="") { - tooltip->set_markup (ttip); - return true; - } - else - return false; -} - -void ThumbBrowserBase::on_style_changed (const Glib::RefPtr& style) { - // GUI will be acquired by refreshThumbImages - refreshThumbImages (); -} - -ThumbBrowserBase::Internal::Internal () : ofsX(0), ofsY(0), parent(NULL), dirty(true) { -} - -void ThumbBrowserBase::Internal::setParent (ThumbBrowserBase* p) { - parent = p; -} - -void ThumbBrowserBase::Internal::setPosition (int x, int y) { - ofsX = x; - ofsY = y; -} - -bool ThumbBrowserBase::Internal::on_key_press_event (GdkEventKey* event) { - // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) - return parent->keyPressed (event); -} - -bool ThumbBrowserBase::Internal::on_button_press_event (GdkEventButton* event) { - // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) - grab_focus (); - - parent->eventTime = event->time; - - parent->buttonPressed ((int)event->x, (int)event->y, event->button, event->type, event->state, 0, 0, get_width(), get_height()); - Glib::RefPtr window = get_window(); - - GdkRectangle rect; - rect.x = 0; - rect.y = 0; - window->get_size (rect.width, rect.height); - - gdk_window_invalidate_rect (window->gobj(), &rect, true); - gdk_window_process_updates (window->gobj(), true); - - return true; -} - -void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType type, int state, int clx, int cly, int clw, int clh) { - // GUI already acquired - - ThumbBrowserEntryBase* fileDescr = NULL; - bool handled = false; - - { - #if PROTECT_VECTORS - MYREADERLOCK(l, entryRW); - #endif - for (size_t i=0; idrawable) { - if (fd[i]->inside (x, y) && fd[i]->insideWindow (clx, cly, clw, clh)) - fileDescr = fd[i]; - bool b = fd[i]->pressNotify (button, type, state, x, y); - handled = handled || b; - } - } - - if (handled || (fileDescr && fileDescr->processing)) - return; - - { - #if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); - #endif - - if (selected.size()==1 && type==GDK_2BUTTON_PRESS && button==1) - doubleClicked (selected[0]); - else if (button==1 && type==GDK_BUTTON_PRESS) { - if (fileDescr && (state & GDK_SHIFT_MASK)) { - if (selected.empty()) { - selected.push_back (fileDescr); - fileDescr->selected = true; - lastClicked = fileDescr; - #if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); - #endif - selectionChanged (); - } - else { - // find the start and the end of the selection interval - size_t startx = fd.size()-1; - if (lastClicked) { - for (; startx>0; startx--) - if (fd[startx]==lastClicked) - break; - } - else { - for (; startx>0; startx--) - if (fd[startx]==selected[0]) - break; - } - size_t endx = 0; - for (; endxselected = false; - selected.clear (); - // select thumbnails in the interval - for (size_t i=startx; i<=endx; i++) { - if (!fd[i]->filtered) { - fd[i]->selected = true; - selected.push_back (fd[i]); - } - } - lastClicked = fileDescr; - #if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); - #endif - selectionChanged (); - } - } - else if (fileDescr && (state & GDK_CONTROL_MASK)) { - std::vector::iterator i = std::find (selected.begin(), selected.end(), fileDescr); - if (i!=selected.end()) { - (*i)->selected = false; - selected.erase (i); - } - else { - selected.push_back (fileDescr); - fileDescr->selected = true; - } - lastClicked = fileDescr; - #if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); - #endif - selectionChanged (); - } - else { - for (size_t i=0; iselected = false; - selected.clear (); - if (fileDescr) { - selected.push_back (fileDescr); - fileDescr->selected = true; - } - lastClicked = fileDescr; - #if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); - #endif - selectionChanged (); - } - } - else if (fileDescr && button==3 && type==GDK_BUTTON_PRESS) { - if (!fileDescr->selected) { - for (size_t i=0; iselected = false; - selected.clear (); - fileDescr->selected = true; - selected.push_back (fileDescr); - lastClicked = fileDescr; - #if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); - #endif - selectionChanged (); - } - #if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); - #endif - rightClicked (fileDescr); - } - } // end of MYWRITERLOCK(l, entryRW); - -} - -bool ThumbBrowserBase::Internal::on_expose_event(GdkEventExpose* event) { - // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) - - dirty = false; - - Glib::RefPtr window = get_window(); - - int w = get_width(); - int h = get_height(); - - window->clear(); - // draw thumbnails - Glib::RefPtr context = get_pango_context (); - context->set_font_description (get_style()->get_font()); - - { - #if PROTECT_VECTORS - MYWRITERLOCK(l, parent->entryRW); - #endif - - for (size_t i=0; ifd.size() && !dirty; i++) { // if dirty meanwhile, cancel and wait for next redraw - if (!parent->fd[i]->drawable || !parent->fd[i]->insideWindow (0, 0, w, h)) - parent->fd[i]->updatepriority = false; - else { - parent->fd[i]->updatepriority = true; - parent->fd[i]->draw (); - } - } - } - - return true; -} - -bool ThumbBrowserBase::Internal::on_button_release_event (GdkEventButton* event) { - // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) - int w = get_width(); - int h = get_height(); - - #if PROTECT_VECTORS - MYREADERLOCK(l, parent->entryRW); - #endif - - for (size_t i=0; ifd.size(); i++) - if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) { - ThumbBrowserEntryBase* tbe = parent->fd[i]; - #if PROTECT_VECTORS - MYREADERLOCK_RELEASE(l); - #endif - // This will require a Writer access... - tbe->releaseNotify (event->button, event->type, event->state, (int)event->x, (int)event->y); - #if PROTECT_VECTORS - MYREADERLOCK_ACQUIRE(l); - #endif - } - return true; -} - -bool ThumbBrowserBase::Internal::on_motion_notify_event (GdkEventMotion* event) { - // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) - int w = get_width(); - int h = get_height(); - - #if PROTECT_VECTORS - MYREADERLOCK(l, parent->entryRW); - #endif - - for (size_t i=0; ifd.size(); i++) - if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) { - /*#if PROTECT_VECTORS - MYREADERLOCK_RELEASE(l); // motionNotify calls the queue, which locks - #endif*/ - parent->fd[i]->motionNotify ((int)event->x, (int)event->y); - } - return true; -} - -bool ThumbBrowserBase::Internal::on_scroll_event (GdkEventScroll* event) { - // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) - - parent->scroll (event->direction); - return true; -} - - -void ThumbBrowserBase::redraw () { - - GThreadLock lock; - arrangeFiles (); - queue_draw (); -} - -void ThumbBrowserBase::zoomChanged (bool zoomIn) { - - int newHeight=0; - int optThumbSize=getThumbnailHeight(); - if (zoomIn) - for (size_t i=0; i optThumbSize) - break; - } - else - for (size_t i=options.thumbnailZoomRatios.size()-1; i>0; i--) { - newHeight = (int)(options.thumbnailZoomRatios[i] * getMaxThumbnailHeight()); - if (newHeight < optThumbSize) - break; - } - previewHeight = newHeight; - - saveThumbnailHeight(newHeight); - - { - #if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); - #endif - - for (size_t i=0; iresize (previewHeight); - } - - redraw (); -#ifdef WIN32 - gdk_window_process_updates (get_window()->gobj(), true); -#endif -} - -void ThumbBrowserBase::refreshThumbImages () { - - int previewHeight = getThumbnailHeight(); - { - #if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); - #endif - - for (size_t i=0; iresize (previewHeight); - } - - redraw (); -} - -void ThumbBrowserBase::refreshQuickThumbImages () { - #if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); - #endif - - for (size_t i=0; irefreshQuickThumbnailImage (); -} - -void ThumbBrowserBase::refreshEditedState (const std::set& efiles) { - - editedFiles = efiles; - { - #if PROTECT_VECTORS - MYREADERLOCK(l, entryRW); - #endif - - for (size_t i=0; iframed = editedFiles.find (fd[i]->filename)!=editedFiles.end(); - } - - queue_draw (); -} - -void ThumbBrowserBase::setArrangement (Arrangement a) { - - arrangement = a; - redraw (); -} - -void ThumbBrowserBase::enableTabMode(bool enable) { - location = enable ? THLOC_EDITOR : THLOC_FILEBROWSER; - arrangement = enable ? ThumbBrowserBase::TB_Horizontal : ThumbBrowserBase::TB_Vertical; - - if ((!options.sameThumbSize && (options.thumbSizeTab!=options.thumbSize)) || (options.showFileNames || options.filmStripShowFileNames)) { - #if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); - #endif - - for (size_t i=0; iresize (getThumbnailHeight()); - } - - redraw (); - - // Scroll to selected position if going into ribbon mode or back - // Tab mode is horizontal, file browser is vertical - { - #if PROTECT_VECTORS - MYREADERLOCK(l, entryRW); - #endif - - if (!selected.empty()) { - if (enable) { - double h=selected[0]->getStartX(); - #if PROTECT_VECTORS - MYREADERLOCK_RELEASE(l); - #endif - hscroll.set_value (min(h, hscroll.get_adjustment()->get_upper())); - } else { - double v=selected[0]->getStartY(); - #if PROTECT_VECTORS - MYREADERLOCK_RELEASE(l); - #endif - vscroll.set_value (min(v, vscroll.get_adjustment()->get_upper())); - } - } - } -} - -void ThumbBrowserBase::initEntry (ThumbBrowserEntryBase* entry) { - entry->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); -} - -void ThumbBrowserBase::getScrollPosition (double& h, double& v) { - h = hscroll.get_value (); - v = vscroll.get_value (); -} - -void ThumbBrowserBase::setScrollPosition (double h, double v) { - hscroll.set_value (h>hscroll.get_adjustment()->get_upper() ? hscroll.get_adjustment()->get_upper() : h); - vscroll.set_value (v>vscroll.get_adjustment()->get_upper() ? vscroll.get_adjustment()->get_upper() : v); -} - -// needed for auto-height in single tab -int ThumbBrowserBase::getEffectiveHeight() { - int h=hscroll.get_height() + 2; // have 2 pixels rounding error for scroll bars to appear - - #if PROTECT_VECTORS - MYREADERLOCK(l, entryRW); - #endif - - // Filtered items do not change in size, so take a non-filtered - for (size_t i=0;ifiltered) { - h+=fd[i]->getEffectiveHeight(); - break; - } - - return h; -} - -void ThumbBrowserBase::redrawNeeded (ThumbBrowserEntryBase* entry) { - - // HOMBRE:DELETE ME? - GThreadLock tLock; // Acquire the GUI - - if (entry->insideWindow (0, 0, internal.get_width(), internal.get_height())) { - if (!internal.isDirty ()) { - internal.setDirty (); - internal.queue_draw (); - } - } -} - - +/* + * This file is part of RawTherapee. + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include +#include "../rtengine/rt_math.h" + +#include "thumbbrowserbase.h" +#include "multilangmgr.h" +#include "options.h" +#include "../rtengine/mytime.h" + +using namespace std; + +ThumbBrowserBase::ThumbBrowserBase () + : lastClicked(NULL), previewHeight(options.thumbSize), numOfCols(1), inspector(NULL), isInspectorActive(false) { + location = THLOC_FILEBROWSER; + inW = -1; inH = -1; + + Gtk::HBox* hb1 = Gtk::manage( new Gtk::HBox () ); + Gtk::HBox* hb2 = Gtk::manage( new Gtk::HBox () ); + Gtk::Frame* frame = Gtk::manage( new Gtk::Frame () ); + frame->add (internal); + frame->set_shadow_type (Gtk::SHADOW_IN ); + hb1->pack_start (*frame); + hb1->pack_end (vscroll, Gtk::PACK_SHRINK, 0); + + pack_start (*hb1); + + hb2->pack_start (hscroll); + + pack_start (*hb2,Gtk::PACK_SHRINK, 0); + + internal.setParent (this); + + show_all (); + + hscroll.set_update_policy (Gtk::UPDATE_CONTINUOUS); + vscroll.set_update_policy (Gtk::UPDATE_CONTINUOUS); + + vscroll.signal_value_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::scrollChanged) ); + hscroll.signal_value_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::scrollChanged) ); + + internal.signal_size_allocate().connect( sigc::mem_fun(*this, &ThumbBrowserBase::internalAreaResized) ); +} + +void ThumbBrowserBase::scrollChanged () { + { + #if PROTECT_VECTORS + MYWRITERLOCK(l, entryRW); + #endif + + for (size_t i=0; isetOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); + } + + internal.setPosition ((int)(hscroll.get_value()), (int)(vscroll.get_value())); + + if (!internal.isDirty()) { + internal.setDirty (); + internal.queue_draw (); + } +} + +void ThumbBrowserBase::scroll (int direction) { + // GUI already acquired when here + if (arrangement==TB_Vertical) + vscroll.set_value (vscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * vscroll.get_adjustment()->get_step_increment()); + else + hscroll.set_value (hscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * hscroll.get_adjustment()->get_step_increment()); +} + +void ThumbBrowserBase::scrollPage (int direction) { + // GUI already acquired when here + if (arrangement==TB_Vertical) + vscroll.set_value (vscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * vscroll.get_adjustment()->get_page_increment()); + else + hscroll.set_value (hscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * hscroll.get_adjustment()->get_page_increment()); +} + +static void scrollToEntry (double& h, double& v, int iw, int ih, ThumbBrowserEntryBase* entry) { + const int hmin = entry->getX (); + const int hmax = hmin + entry->getEffectiveWidth () - iw; + const int vmin = entry->getY (); + const int vmax = vmin + entry->getEffectiveHeight () - ih; + + if (hmin < 0) + h += hmin; + else if (hmax > 0) + h += hmax; + + if(vmin < 0) + v += vmin; + else if (vmax > 0) + v += vmax; +} + +void ThumbBrowserBase::selectPrev (int distance, bool enlarge) { + double h, v; + getScrollPosition (h, v); + + { + #if PROTECT_VECTORS + MYWRITERLOCK(l, entryRW); + #endif + + if (!selected.empty ()) { + std::vector::iterator front = std::find (fd.begin (), fd.end (), selected.front ()); + std::vector::iterator back = std::find (fd.begin (), fd.end (), selected.back ()); + std::vector::iterator last = std::find (fd.begin (), fd.end (), lastClicked); + + if (front > back) + std::swap(front, back); + + std::vector::iterator& curr = last == front ? front : back; + + // find next thumbnail at filtered distance before current + for (; curr >= fd.begin (); --curr) { + if (!(*curr)->filtered) { + if (distance-- == 0) { + // clear current selection + for (size_t i=0; iselected = false; + redrawNeeded (selected[i]); + } + selected.clear (); + + // make sure the newly selected thumbnail is visible and make it current + scrollToEntry (h, v, internal.get_width (), internal.get_height (), *curr); + lastClicked = *curr; + + // either enlarge current selection or set new selection + if(enlarge) { + // reverse direction if distance is too large + if(front > back) + std::swap(front, back); + + for (; front <= back; ++front) { + if (!(*front)->filtered) { + (*front)->selected = true; + redrawNeeded (*front); + selected.push_back (*front); + } + } + } + else { + (*curr)->selected = true; + redrawNeeded (*curr); + selected.push_back (*curr); + } + + break; + } + } + } + } + + #if PROTECT_VECTORS + MYWRITERLOCK_RELEASE(l); + #endif + selectionChanged (); + } + + setScrollPosition (h, v); +} + +void ThumbBrowserBase::selectNext (int distance, bool enlarge) { + double h, v; + getScrollPosition (h, v); + + { + #if PROTECT_VECTORS + MYWRITERLOCK(l, entryRW); + #endif + + if (!selected.empty ()) { + std::vector::iterator front = std::find (fd.begin (), fd.end (), selected.front ()); + std::vector::iterator back = std::find (fd.begin (), fd.end (), selected.back ()); + std::vector::iterator last = std::find (fd.begin (), fd.end (), lastClicked); + + if (front > back) + std::swap(front, back); + + std::vector::iterator& curr = last == back ? back : front; + + // find next thumbnail at filtered distance after current + for (; curr < fd.end (); ++curr) { + if (!(*curr)->filtered) { + if (distance-- == 0) { + // clear current selection + for (size_t i=0; iselected = false; + redrawNeeded (selected[i]); + } + selected.clear (); + + // make sure the newly selected thumbnail is visible and make it current + scrollToEntry (h, v, internal.get_width (), internal.get_height (), *curr); + lastClicked = *curr; + + // either enlarge current selection or set new selection + if(enlarge) { + // reverse direction if distance is too large + if(front > back) + std::swap(front, back); + + for (; front <= back; ++front) { + if (!(*front)->filtered) { + (*front)->selected = true; + redrawNeeded (*front); + selected.push_back (*front); + } + } + } + else { + (*curr)->selected = true; + redrawNeeded (*curr); + selected.push_back (*curr); + } + + break; + } + } + } + } + + #if PROTECT_VECTORS + MYWRITERLOCK_RELEASE(l); + #endif + selectionChanged (); + } + + setScrollPosition (h, v); +} + +void ThumbBrowserBase::selectFirst (bool enlarge) { + double h, v; + getScrollPosition (h, v); + + { + #if PROTECT_VECTORS + MYWRITERLOCK(l, entryRW); + #endif + + if (!fd.empty ()) { + // find first unfiltered entry + std::vector::iterator first = fd.begin (); + + for (; first < fd.end (); ++first) { + if (!(*first)->filtered) { + break; + } + } + + scrollToEntry (h, v, internal.get_width (), internal.get_height (), *first); + + ThumbBrowserEntryBase* lastEntry = lastClicked; + lastClicked = *first; + + if(selected.empty ()) { + (*first)->selected = true; + redrawNeeded (*first); + selected.push_back (*first); + } + else { + std::vector::iterator back = std::find (fd.begin (), fd.end (), lastEntry ? lastEntry : selected.back ()); + + if (first > back) + std::swap(first, back); + + // clear current selection + for (size_t i=0; iselected = false; + redrawNeeded (selected[i]); + } + selected.clear (); + + // either enlarge current selection or set new selection + for (; first <= back; ++first) { + if (!(*first)->filtered) { + (*first)->selected = true; + redrawNeeded (*first); + selected.push_back (*first); + } + + if (!enlarge) + break; + } + } + } + + #if PROTECT_VECTORS + MYWRITERLOCK_RELEASE(l); + #endif + selectionChanged (); + } + + setScrollPosition (h, v); +} + +void ThumbBrowserBase::selectLast (bool enlarge) { + double h, v; + getScrollPosition (h, v); + + { + #if PROTECT_VECTORS + MYWRITERLOCK(l, entryRW); + #endif + + if (!fd.empty ()) { + // find last unfiltered entry + std::vector::iterator last = fd.end () - 1; + + for (; last >= fd.begin (); --last) { + if (!(*last)->filtered) { + break; + } + } + + scrollToEntry (h, v, internal.get_width (), internal.get_height (), *last); + + ThumbBrowserEntryBase* lastEntry = lastClicked; + lastClicked = *last; + + if(selected.empty()) { + (*last)->selected = true; + redrawNeeded (*last); + selected.push_back (*last); + } + else { + std::vector::iterator front = std::find (fd.begin (), fd.end (), lastEntry ? lastEntry : selected.front ()); + + if (last < front) + std::swap(last, front); + + // clear current selection + for (size_t i=0; iselected = false; + redrawNeeded (selected[i]); + } + selected.clear (); + + // either enlarge current selection or set new selection + for (; front <= last; --last) { + if (!(*last)->filtered) { + (*last)->selected = true; + redrawNeeded (*last); + selected.push_back (*last); + } + + if (!enlarge) + break; + } + + std::reverse(selected.begin (), selected.end ()); + } + } + + #if PROTECT_VECTORS + MYWRITERLOCK_RELEASE(l); + #endif + selectionChanged (); + } + + setScrollPosition (h, v); +} + +void ThumbBrowserBase::resizeThumbnailArea (int w, int h) { + + inW = w; + inH = h; + + if (hscroll.get_value() + internal.get_width() > inW) + hscroll.set_value (inW - internal.get_width()); + if (vscroll.get_value() + internal.get_height() > inH) + vscroll.set_value (inH - internal.get_height()); + + configScrollBars (); +} + +void ThumbBrowserBase::internalAreaResized (Gtk::Allocation& req) { + + if (inW>0 && inH>0) { + configScrollBars (); + redraw (); + } +} + +void ThumbBrowserBase::configScrollBars () { + + // HOMBRE:DELETE ME? + GThreadLock tLock; // Acquire the GUI + + if (inW>0 && inH>0) { + + int iw = internal.get_width (); + int ih = internal.get_height (); + + hscroll.get_adjustment()->set_upper (inW); + vscroll.get_adjustment()->set_upper (inH); + hscroll.get_adjustment()->set_lower (0); + vscroll.get_adjustment()->set_lower (0); + hscroll.get_adjustment()->set_step_increment (32); + vscroll.get_adjustment()->set_step_increment (32); + hscroll.get_adjustment()->set_page_increment (iw); + vscroll.get_adjustment()->set_page_increment (ih); + hscroll.get_adjustment()->set_page_size (iw); + vscroll.get_adjustment()->set_page_size (ih); + + if(iw>=inW) + hscroll.hide(); + else + hscroll.show(); + + if(ih>=inH) + vscroll.hide(); + else + vscroll.show(); + } +} + +void ThumbBrowserBase::arrangeFiles () { + + #if PROTECT_VECTORS + MYREADERLOCK(l, entryRW); + #endif + + // GUI already locked by ::redraw, the only caller of this method for now. + // We could lock it one more time, there's no harm excepted (negligible) speed penalty + //GThreadLock lock; + + int N = fd.size (); + // apply filter + for (int i=0; ifiltered = !checkFilter (fd[i]); + + int rowHeight = 0; + // compute size of the items + for (int i=0; ifiltered && fd[i]->getMinimalHeight() > rowHeight) + rowHeight = fd[i]->getMinimalHeight (); + + if (arrangement==TB_Horizontal) { + numOfCols = 1; + int numOfRows = 1; +// if (rowHeight>0) { +// numOfRows = (internal.get_height()+rowHeight/2)/rowHeight; +// if (numOfRows<1) +// numOfRows = 1; +// } + + int ct = 0; + int currx = 0; int curry = 0; + while (ctgetMinimalWidth() > maxw) + maxw = fd[ct+i]->getMinimalWidth (); + + // arrange items in the column + curry = 0; + for (int i=0; ctfiltered) + fd[ct++]->drawable = false; + if (ctsetPosition (currx, curry, maxw, rowHeight); + fd[ct]->drawable = true; + curry += rowHeight; + } + } + currx += maxw; + } + #if PROTECT_VECTORS + MYREADERLOCK_RELEASE(l); + #endif + // This will require a Writer access + resizeThumbnailArea (currx, numOfRows*rowHeight); + } + else { + int availWidth = internal.get_width(); + // initial number of columns + numOfCols = 0; + int colsWidth = 0; + for (int i=0; ifiltered && colsWidth + fd[i]->getMinimalWidth() <= availWidth) { + colsWidth += fd[numOfCols]->getMinimalWidth (); + numOfCols++; + } + if (numOfCols<1) + numOfCols = 1; + std::vector colWidths; + for (; numOfCols>0; numOfCols--) { + // compute column widths + colWidths.resize (numOfCols); + for (int i=0; ifiltered && fd[i]->getMinimalWidth() > colWidths[j%numOfCols]) + colWidths[j%numOfCols] = fd[i]->getMinimalWidth (); + if (!fd[i]->filtered) + j++; + } + // if not wider than the space available, arrange it and we are ready + colsWidth = 0; + for (int i=0; ifiltered) + fd[ct++]->drawable = false; + if (ctsetPosition (currx, curry, colWidths[i%numOfCols], rowHeight); + fd[ct]->drawable = true; + currx += colWidths[i%numOfCols]; + } + } + if (currx>0) // there were thumbnails placed in the row + curry += rowHeight; + } + #if PROTECT_VECTORS + MYREADERLOCK_RELEASE(l); + #endif + // This will require a Writer access + resizeThumbnailArea (colsWidth, curry); + } +} + +void ThumbBrowserBase::disableInspector() { + if (inspector) + inspector->setActive(false); +} + +void ThumbBrowserBase::enableInspector() { + if (inspector) + inspector->setActive(true); +} + +void ThumbBrowserBase::Internal::on_realize() { + // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) + Cairo::FontOptions cfo; + cfo.set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + get_pango_context()->set_cairo_font_options (cfo); + + Gtk::DrawingArea::on_realize(); + Glib::RefPtr window = get_window(); + set_flags (Gtk::CAN_FOCUS); + add_events(Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK); + gc_ = Gdk::GC::create(window); + set_has_tooltip (true); + signal_query_tooltip().connect( sigc::mem_fun(*this, &ThumbBrowserBase::Internal::on_query_tooltip) ); +} + +bool ThumbBrowserBase::Internal::on_query_tooltip (int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) { + // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) + Glib::ustring ttip = ""; + + { + #if PROTECT_VECTORS + MYREADERLOCK(l, parent->entryRW); + #endif + + for (size_t i=0; ifd.size(); i++) + if (parent->fd[i]->drawable && parent->fd[i]->inside (x, y)) { + ttip = parent->fd[i]->getToolTip (x, y); + break; + } + } + if (ttip!="") { + tooltip->set_markup (ttip); + return true; + } + else + return false; +} + +void ThumbBrowserBase::on_style_changed (const Glib::RefPtr& style) { + // GUI will be acquired by refreshThumbImages + refreshThumbImages (); +} + +ThumbBrowserBase::Internal::Internal () : ofsX(0), ofsY(0), parent(NULL), dirty(true) { +} + +void ThumbBrowserBase::Internal::setParent (ThumbBrowserBase* p) { + parent = p; +} + +void ThumbBrowserBase::Internal::setPosition (int x, int y) { + ofsX = x; + ofsY = y; +} + +bool ThumbBrowserBase::Internal::on_key_press_event (GdkEventKey* event) { + // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) + return parent->keyPressed (event); +} + +bool ThumbBrowserBase::Internal::on_button_press_event (GdkEventButton* event) { + // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) + grab_focus (); + + parent->eventTime = event->time; + + parent->buttonPressed ((int)event->x, (int)event->y, event->button, event->type, event->state, 0, 0, get_width(), get_height()); + Glib::RefPtr window = get_window(); + + GdkRectangle rect; + rect.x = 0; + rect.y = 0; + window->get_size (rect.width, rect.height); + + gdk_window_invalidate_rect (window->gobj(), &rect, true); + gdk_window_process_updates (window->gobj(), true); + + return true; +} + +void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType type, int state, int clx, int cly, int clw, int clh) { + // GUI already acquired + + ThumbBrowserEntryBase* fileDescr = NULL; + bool handled = false; + + { + #if PROTECT_VECTORS + MYREADERLOCK(l, entryRW); + #endif + for (size_t i=0; idrawable) { + if (fd[i]->inside (x, y) && fd[i]->insideWindow (clx, cly, clw, clh)) + fileDescr = fd[i]; + bool b = fd[i]->pressNotify (button, type, state, x, y); + handled = handled || b; + } + } + + if (handled || (fileDescr && fileDescr->processing)) + return; + + { + #if PROTECT_VECTORS + MYWRITERLOCK(l, entryRW); + #endif + + if (selected.size()==1 && type==GDK_2BUTTON_PRESS && button==1) + doubleClicked (selected[0]); + else if (button==1 && type==GDK_BUTTON_PRESS) { + if (fileDescr && (state & GDK_SHIFT_MASK)) { + if (selected.empty()) { + selected.push_back (fileDescr); + fileDescr->selected = true; + lastClicked = fileDescr; + #if PROTECT_VECTORS + MYWRITERLOCK_RELEASE(l); + #endif + selectionChanged (); + } + else { + // find the start and the end of the selection interval + size_t startx = fd.size()-1; + if (lastClicked) { + for (; startx>0; startx--) + if (fd[startx]==lastClicked) + break; + } + else { + for (; startx>0; startx--) + if (fd[startx]==selected[0]) + break; + } + size_t endx = 0; + for (; endxselected = false; + selected.clear (); + // select thumbnails in the interval + for (size_t i=startx; i<=endx; i++) { + if (!fd[i]->filtered) { + fd[i]->selected = true; + selected.push_back (fd[i]); + } + } + lastClicked = fileDescr; + #if PROTECT_VECTORS + MYWRITERLOCK_RELEASE(l); + #endif + selectionChanged (); + } + } + else if (fileDescr && (state & GDK_CONTROL_MASK)) { + std::vector::iterator i = std::find (selected.begin(), selected.end(), fileDescr); + if (i!=selected.end()) { + (*i)->selected = false; + selected.erase (i); + } + else { + selected.push_back (fileDescr); + fileDescr->selected = true; + } + lastClicked = fileDescr; + #if PROTECT_VECTORS + MYWRITERLOCK_RELEASE(l); + #endif + selectionChanged (); + } + else { + for (size_t i=0; iselected = false; + selected.clear (); + if (fileDescr) { + selected.push_back (fileDescr); + fileDescr->selected = true; + } + lastClicked = fileDescr; + #if PROTECT_VECTORS + MYWRITERLOCK_RELEASE(l); + #endif + selectionChanged (); + } + } + else if (fileDescr && button==3 && type==GDK_BUTTON_PRESS) { + if (!fileDescr->selected) { + for (size_t i=0; iselected = false; + selected.clear (); + fileDescr->selected = true; + selected.push_back (fileDescr); + lastClicked = fileDescr; + #if PROTECT_VECTORS + MYWRITERLOCK_RELEASE(l); + #endif + selectionChanged (); + } + #if PROTECT_VECTORS + MYWRITERLOCK_RELEASE(l); + #endif + rightClicked (fileDescr); + } + } // end of MYWRITERLOCK(l, entryRW); + +} + +bool ThumbBrowserBase::Internal::on_expose_event(GdkEventExpose* event) { + // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) + + dirty = false; + + Glib::RefPtr window = get_window(); + + int w = get_width(); + int h = get_height(); + + window->clear(); + // draw thumbnails + Glib::RefPtr context = get_pango_context (); + context->set_font_description (get_style()->get_font()); + + { + #if PROTECT_VECTORS + MYWRITERLOCK(l, parent->entryRW); + #endif + + for (size_t i=0; ifd.size() && !dirty; i++) { // if dirty meanwhile, cancel and wait for next redraw + if (!parent->fd[i]->drawable || !parent->fd[i]->insideWindow (0, 0, w, h)) + parent->fd[i]->updatepriority = false; + else { + parent->fd[i]->updatepriority = true; + parent->fd[i]->draw (); + } + } + } + + return true; +} + +bool ThumbBrowserBase::Internal::on_button_release_event (GdkEventButton* event) { + // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) + int w = get_width(); + int h = get_height(); + + #if PROTECT_VECTORS + MYREADERLOCK(l, parent->entryRW); + #endif + + for (size_t i=0; ifd.size(); i++) + if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) { + ThumbBrowserEntryBase* tbe = parent->fd[i]; + #if PROTECT_VECTORS + MYREADERLOCK_RELEASE(l); + #endif + // This will require a Writer access... + tbe->releaseNotify (event->button, event->type, event->state, (int)event->x, (int)event->y); + #if PROTECT_VECTORS + MYREADERLOCK_ACQUIRE(l); + #endif + } + return true; +} + +bool ThumbBrowserBase::Internal::on_motion_notify_event (GdkEventMotion* event) { + // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) + int w = get_width(); + int h = get_height(); + + #if PROTECT_VECTORS + MYREADERLOCK(l, parent->entryRW); + #endif + + for (size_t i=0; ifd.size(); i++) + if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h)) { + /*#if PROTECT_VECTORS + MYREADERLOCK_RELEASE(l); // motionNotify calls the queue, which locks + #endif*/ + parent->fd[i]->motionNotify ((int)event->x, (int)event->y); + } + return true; +} + +bool ThumbBrowserBase::Internal::on_scroll_event (GdkEventScroll* event) { + // Gtk signals automatically acquire the GUI (i.e. this method is enclosed by gdk_thread_enter and gdk_thread_leave) + + parent->scroll (event->direction); + return true; +} + + +void ThumbBrowserBase::redraw () { + + GThreadLock lock; + arrangeFiles (); + queue_draw (); +} + +void ThumbBrowserBase::zoomChanged (bool zoomIn) { + + int newHeight=0; + int optThumbSize=getThumbnailHeight(); + if (zoomIn) + for (size_t i=0; i optThumbSize) + break; + } + else + for (size_t i=options.thumbnailZoomRatios.size()-1; i>0; i--) { + newHeight = (int)(options.thumbnailZoomRatios[i] * getMaxThumbnailHeight()); + if (newHeight < optThumbSize) + break; + } + previewHeight = newHeight; + + saveThumbnailHeight(newHeight); + + { + #if PROTECT_VECTORS + MYWRITERLOCK(l, entryRW); + #endif + + for (size_t i=0; iresize (previewHeight); + } + + redraw (); +#ifdef WIN32 + gdk_window_process_updates (get_window()->gobj(), true); +#endif +} + +void ThumbBrowserBase::refreshThumbImages () { + + int previewHeight = getThumbnailHeight(); + { + #if PROTECT_VECTORS + MYWRITERLOCK(l, entryRW); + #endif + + for (size_t i=0; iresize (previewHeight); + } + + redraw (); +} + +void ThumbBrowserBase::refreshQuickThumbImages () { + #if PROTECT_VECTORS + MYWRITERLOCK(l, entryRW); + #endif + + for (size_t i=0; irefreshQuickThumbnailImage (); +} + +void ThumbBrowserBase::refreshEditedState (const std::set& efiles) { + + editedFiles = efiles; + { + #if PROTECT_VECTORS + MYREADERLOCK(l, entryRW); + #endif + + for (size_t i=0; iframed = editedFiles.find (fd[i]->filename)!=editedFiles.end(); + } + + queue_draw (); +} + +void ThumbBrowserBase::setArrangement (Arrangement a) { + + arrangement = a; + redraw (); +} + +void ThumbBrowserBase::enableTabMode(bool enable) { + location = enable ? THLOC_EDITOR : THLOC_FILEBROWSER; + arrangement = enable ? ThumbBrowserBase::TB_Horizontal : ThumbBrowserBase::TB_Vertical; + + if ((!options.sameThumbSize && (options.thumbSizeTab!=options.thumbSize)) || (options.showFileNames || options.filmStripShowFileNames)) { + #if PROTECT_VECTORS + MYWRITERLOCK(l, entryRW); + #endif + + for (size_t i=0; iresize (getThumbnailHeight()); + } + + redraw (); + + // Scroll to selected position if going into ribbon mode or back + // Tab mode is horizontal, file browser is vertical + { + #if PROTECT_VECTORS + MYREADERLOCK(l, entryRW); + #endif + + if (!selected.empty()) { + if (enable) { + double h=selected[0]->getStartX(); + #if PROTECT_VECTORS + MYREADERLOCK_RELEASE(l); + #endif + hscroll.set_value (min(h, hscroll.get_adjustment()->get_upper())); + } else { + double v=selected[0]->getStartY(); + #if PROTECT_VECTORS + MYREADERLOCK_RELEASE(l); + #endif + vscroll.set_value (min(v, vscroll.get_adjustment()->get_upper())); + } + } + } +} + +void ThumbBrowserBase::initEntry (ThumbBrowserEntryBase* entry) { + entry->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); +} + +void ThumbBrowserBase::getScrollPosition (double& h, double& v) { + h = hscroll.get_value (); + v = vscroll.get_value (); +} + +void ThumbBrowserBase::setScrollPosition (double h, double v) { + hscroll.set_value (h>hscroll.get_adjustment()->get_upper() ? hscroll.get_adjustment()->get_upper() : h); + vscroll.set_value (v>vscroll.get_adjustment()->get_upper() ? vscroll.get_adjustment()->get_upper() : v); +} + +// needed for auto-height in single tab +int ThumbBrowserBase::getEffectiveHeight() { + int h=hscroll.get_height() + 2; // have 2 pixels rounding error for scroll bars to appear + + #if PROTECT_VECTORS + MYREADERLOCK(l, entryRW); + #endif + + // Filtered items do not change in size, so take a non-filtered + for (size_t i=0;ifiltered) { + h+=fd[i]->getEffectiveHeight(); + break; + } + + return h; +} + +void ThumbBrowserBase::redrawNeeded (ThumbBrowserEntryBase* entry) { + + // HOMBRE:DELETE ME? + GThreadLock tLock; // Acquire the GUI + + if (entry->insideWindow (0, 0, internal.get_width(), internal.get_height())) { + if (!internal.isDirty ()) { + internal.setDirty (); + internal.queue_draw (); + } + } +} + + diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 3de27c54a..d81b2fd55 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -1,920 +1,920 @@ -/* - * This file is part of RawTherapee. - * - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "multilangmgr.h" -#include "thumbnail.h" -#include -#include -#include "options.h" -#include "../rtengine/mytime.h" -#include -#include -#include -#include "../rtengine/imagedata.h" -#include -#include "guiutils.h" -#include "profilestore.h" -#include "batchqueue.h" -#include "../rtengine/safegtk.h" - -using namespace rtengine::procparams; - -Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) - : fname(fname), cfs(*cf), cachemgr(cm), ref(1), enqueueNumber(0), tpp(NULL), - pparamsValid(false), needsReProcessing(true),imageLoading(false), lastImg(NULL), - lastW(0), lastH(0), lastScale(0), initial_(false) -{ - - loadProcParams (); - - // should be safe to use the unprotected version of loadThumbnail, since we are in the constructor - _loadThumbnail (); - generateExifDateTimeStrings (); - - if (cfs.rankOld >= 0){ - // rank and inTrash were found in cache (old style), move them over to pparams - - // try to load the last saved parameters from the cache or from the paramfile file - createProcParamsForUpdate(false, false); // this can execute customprofilebuilder to generate param file - - // TODO? should we call notifylisterners_procParamsChanged here? - - setRank(cfs.rankOld); - setStage(cfs.inTrashOld); - } - - delete tpp; - tpp = 0; -} - -Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5) - : fname(fname), cachemgr(cm), ref(1), enqueueNumber(0), tpp(NULL), pparamsValid(false), - needsReProcessing(true),imageLoading(false), lastImg(NULL), - initial_(true) -{ - - - cfs.md5 = md5; - loadProcParams (); - _generateThumbnailImage (); - cfs.recentlySaved = false; - - initial_ = false; - - delete tpp; - tpp = 0; -} - -void Thumbnail::_generateThumbnailImage () { - - // delete everything loaded into memory - delete tpp; - tpp = NULL; - delete [] lastImg; - lastImg = NULL; - tw = -1; - th = options.maxThumbnailHeight; - imgRatio = -1.; - - // generate thumbnail image - Glib::ustring ext = getExtension (fname); - if (ext=="") - return; - cfs.supported = false; - cfs.exifValid = false; - cfs.timeValid = false; - - if (ext.lowercase()=="jpg" || ext.lowercase()=="jpeg") { - infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams.wb.equal); - if (tpp) - cfs.format = FT_Jpeg; - } - else if (ext.lowercase()=="png") { - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams.wb.equal); - if (tpp) - cfs.format = FT_Png; - } - else if (ext.lowercase()=="tif" || ext.lowercase()=="tiff") { - infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams.wb.equal); - if (tpp) - cfs.format = FT_Tiff; - } - else { - // RAW works like this: - // 1. if we are here it's because we aren't in the cache so load the JPG - // image out of the RAW. Mark as "quick". - // 2. if we don't find that then just grab the real image. - bool quick = false; - rtengine::RawMetaDataLocation ri; - if ( initial_ && options.internalThumbIfUntouched) - { - quick = true; - tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, tw, th, 1, TRUE); - } - if ( tpp == NULL ) - { - quick = false; - tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1, pparams.wb.equal, TRUE); - } - if (tpp) { - cfs.format = FT_Raw; - cfs.thumbImgType = quick ? CacheImageData::QUICK_THUMBNAIL : CacheImageData::FULL_THUMBNAIL; - infoFromImage (fname, &ri); - } - } - - if (tpp) - { - tpp->getAutoWBMultipliers(cfs.redAWBMul, cfs.greenAWBMul, cfs.blueAWBMul); - _saveThumbnail (); - cfs.supported = true; - needsReProcessing = true; - - cfs.save (getCacheFileName ("data")+".txt"); - - generateExifDateTimeStrings (); - } -} - -bool Thumbnail::isSupported () { - return cfs.supported; -} - -const ProcParams& Thumbnail::getProcParams () { - MyMutex::MyLock lock(mutex); - return getProcParamsU(); -} - -// Unprotected version of getProcParams, when -const ProcParams& Thumbnail::getProcParamsU () { - if (pparamsValid) - return pparams; - else { - pparams = *(profileStore.getDefaultProcParams (getType()==FT_Raw)); - if (pparams.wb.method=="Camera") { - double ct; - getCamWB (ct, pparams.wb.green); - pparams.wb.temperature = ct; - } - else if (pparams.wb.method=="Auto") { - double ct; - getAutoWB (ct, pparams.wb.green, pparams.wb.equal); - pparams.wb.temperature = ct; - } - } - return pparams; // there is no valid pp to return, but we have to return something -} - -/** @brief Create default params on demand and returns a new updatable object - * - * The loaded profile may be partial, but it return a complete ProcParams (i.e. without ParamsEdited) - * - * @param returnParams Ask to return a pointer to a ProcParams object if true - * @param forceCPB True if the Custom Profile Builder has to be invoked, False if the CPB has to be invoked if the profile doesn't - * exist yet. It depends on other conditions too - * @param flaggingMode True if the ProcParams will be created because the file browser is being flagging an image - * (rang, to trash, color labels). This parameter is passed to the CPB. - * - * @return Return a pointer to a ProcPamas structure to be updated if returnParams is true and if everything went fine, NULL otherwise. - */ -rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool returnParams, bool forceCPB, bool flaggingMode) { - - static int index=0; // Will act as unique identifier during the session - - // try to load the last saved parameters from the cache or from the paramfile file - ProcParams* ldprof = NULL; - - Glib::ustring defProf = getType()==FT_Raw ? options.defProfRaw : options.defProfImg; - - const CacheImageData* cfs=getCacheImageData(); - Glib::ustring defaultPparamsPath = options.findProfilePath(defProf); - if (!options.CPBPath.empty() && !defaultPparamsPath.empty() && (!hasProcParams() || forceCPB) && cfs && cfs->exifValid) { - // First generate the communication file, with general values and EXIF metadata - rtengine::ImageMetaData* imageMetaData; - if (getType()==FT_Raw) { - rtengine::RawMetaDataLocation metaData = rtengine::Thumbnail::loadMetaDataFromRaw(fname); - imageMetaData = rtengine::ImageMetaData::fromFile (fname, &metaData); - } - else - imageMetaData = rtengine::ImageMetaData::fromFile (fname, NULL); - - Glib::ustring tmpFileName( Glib::build_filename(options.cacheBaseDir, Glib::ustring::compose("CPB_temp_%1.txt", index++)) ); - - const rtexif::TagDirectory* exifDir=NULL; - if (imageMetaData && (exifDir = imageMetaData->getExifData())) { - Glib::ustring outFName; - if (options.paramsLoadLocation==PLL_Input) - outFName = fname+paramFileExtension; - else - outFName = getCacheFileName("profiles")+paramFileExtension; - exifDir->CPBDump(tmpFileName, fname, outFName, - defaultPparamsPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(defaultPparamsPath, Glib::path_get_basename(defProf) + paramFileExtension), - cfs, - flaggingMode); - } - - // For the filename etc. do NOT use streams, since they are not UTF8 safe - Glib::ustring cmdLine = options.CPBPath + Glib::ustring(" \"") + tmpFileName + Glib::ustring("\""); - - if (options.rtSettings.verbose) - printf("Custom profile builder's command line: %s\n", Glib::ustring(cmdLine).c_str()); - bool success = safe_spawn_command_line_sync (cmdLine); - - // Now they SHOULD be there (and potentially "partial"), so try to load them and store it as a full procparam - if (success) loadProcParams(); - - if (safe_file_test(tmpFileName, Glib::FILE_TEST_EXISTS )) safe_g_remove (tmpFileName); - - if (imageMetaData) delete imageMetaData; - } - - if (returnParams && hasProcParams()) { - ldprof = new ProcParams (); - *ldprof = getProcParams (); - } - - return ldprof; -} - -void Thumbnail::notifylisterners_procParamsChanged(int whoChangedIt){ - for (size_t i=0; iprocParamsChanged (this, whoChangedIt); -} - -/* - * Load the procparams from the cache or from the sidecar file (priority set in - * the Preferences). - * - * The result is a complete ProcParams with default values merged with the values - * from the default Raw or Image ProcParams, then with the values from the loaded - * ProcParams (sidecar or cache file). - */ -void Thumbnail::loadProcParams () { - MyMutex::MyLock lock(mutex); - - pparamsValid = false; - pparams.setDefaults(); - const PartialProfile *defaultPP = profileStore.getDefaultPartialProfile(getType()==FT_Raw); - defaultPP->applyTo(&pparams); - - if (options.paramsLoadLocation==PLL_Input) { - // try to load it from params file next to the image file - int ppres = pparams.load (fname + paramFileExtension); - pparamsValid = !ppres && pparams.ppVersion>=220; - // if no success, try to load the cached version of the procparams - if (!pparamsValid) - pparamsValid = !pparams.load (getCacheFileName ("profiles")+paramFileExtension); - } - else { - // try to load it from cache - pparamsValid = !pparams.load (getCacheFileName ("profiles")+paramFileExtension); - // if no success, try to load it from params file next to the image file - if (!pparamsValid) { - int ppres = pparams.load (fname + paramFileExtension); - pparamsValid = !ppres && pparams.ppVersion>=220; - } - } -} - -void Thumbnail::clearProcParams (int whoClearedIt) { - -/* Clarification on current "clear profile" functionality: - a. if rank/colorlabel/inTrash are NOT set, - the "clear profile" will delete the pp3 file (as before). - - b. if any of the rank/colorlabel/inTrash ARE set, - the "clear profile" will lead to execution of ProcParams::setDefaults - (the CPB is NOT called) to set the params values and will preserve - rank/colorlabel/inTrash in the param file. */ - - { - MyMutex::MyLock lock(mutex); - - // preserve rank, colorlabel and inTrash across clear - int rank = getRank(); - int colorlabel = getColorLabel(); - int inTrash = getStage(); - - - cfs.recentlySaved = false; - pparamsValid = false; - needsReProcessing = true; - - //TODO: run though customprofilebuilder? - // probably not as this is the only option to set param values to default - - // reset the params to defaults - pparams.setDefaults(); - - // and restore rank and inTrash - setRank(rank); - setColorLabel(colorlabel); - setStage(inTrash); - - // params could get validated by rank/inTrash values restored above - if (pparamsValid) - { - updateCache(); - } - else - { - // remove param file from cache - Glib::ustring fname_ = getCacheFileName ("profiles")+paramFileExtension; - if (safe_file_test (fname_, Glib::FILE_TEST_EXISTS)) - safe_g_remove (fname_); - // remove param file located next to the file -// fname_ = removeExtension(fname) + paramFileExtension; - fname_ = fname + paramFileExtension; - if (safe_file_test(fname_, Glib::FILE_TEST_EXISTS)) - safe_g_remove (fname_); - fname_ = removeExtension(fname) + paramFileExtension; - if (safe_file_test (fname_, Glib::FILE_TEST_EXISTS)) - safe_g_remove (fname_); - - if (cfs.format == FT_Raw && options.internalThumbIfUntouched && cfs.thumbImgType != CacheImageData::QUICK_THUMBNAIL) { - // regenerate thumbnail, ie load the quick thumb again. For the rare formats not supporting quick thumbs this will - // be a bit slow as a new full thumbnail will be generated unnecessarily, but currently there is no way to pre-check - // if the format supports quick thumbs. - initial_ = true; - _generateThumbnailImage(); - initial_ = false; - } - } - - } // end of mutex lock - - for (size_t i=0; iprocParamsChanged (this, whoClearedIt); -} - -bool Thumbnail::hasProcParams () { - - return pparamsValid; -} - -void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoChangedIt, bool updateCacheNow) { - - { - MyMutex::MyLock lock(mutex); - - if (pparams.sharpening.threshold.isDouble() != pp.sharpening.threshold.isDouble()) - printf("WARNING: Sharpening different!\n"); - if (pparams.vibrance.psthreshold.isDouble() != pp.vibrance.psthreshold.isDouble()) - printf("WARNING: Vibrance different!\n"); - - if (pparams!=pp) - cfs.recentlySaved = false; - - // do not update rank, colorlabel and inTrash - int rank = getRank(); - int colorlabel = getColorLabel(); - int inTrash = getStage(); - - if (pe) { - pe->combine(pparams, pp, true); - } - else pparams = pp; - pparamsValid = true; - needsReProcessing = true; - - setRank(rank); - setColorLabel(colorlabel); - setStage(inTrash); - - if (updateCacheNow) - updateCache (); - - } // end of mutex lock - - for (size_t i=0; iprocParamsChanged (this, whoChangedIt); -} - -bool Thumbnail::isRecentlySaved () { - - return cfs.recentlySaved; -} - -void Thumbnail::imageDeveloped () { - - cfs.recentlySaved = true; - cfs.save (getCacheFileName ("data")+".txt"); - if (options.saveParamsCache) - pparams.save (getCacheFileName ("profiles")+paramFileExtension); -} - -void Thumbnail::imageEnqueued () { - - enqueueNumber++; -} - -void Thumbnail::imageRemovedFromQueue () { - - enqueueNumber--; -} - -bool Thumbnail::isEnqueued () { - - return enqueueNumber > 0; -} - -void Thumbnail::increaseRef () -{ - MyMutex::MyLock lock(mutex); - ++ref; -} - -void Thumbnail::decreaseRef () -{ - { - MyMutex::MyLock lock(mutex); - if ( ref == 0 ) - { - return; - } - if ( --ref != 0 ) - { - return; - } - } - cachemgr->closeThumbnail (this); -} - -void Thumbnail::getThumbnailSize (int &w, int &h, const rtengine::procparams::ProcParams *pparams) { - int tw_ = tw; - int th_ = th; - float imgRatio_ = imgRatio; - - if (pparams) { - int ppCoarse = pparams->coarse.rotate; - if (ppCoarse >= 180) ppCoarse -= 180; - - int thisCoarse = this->pparams.coarse.rotate; - if (thisCoarse >= 180) thisCoarse -= 180; - - if (thisCoarse != ppCoarse) { - // different orientation -> swapping width & height - int tmp = th_; - th_ = tw_; - tw_ = tmp; - if (imgRatio_ >= 0.0001f) - imgRatio_ = 1.f/imgRatio_; - } - } - - if (imgRatio_ > 0.) - w = (int)(imgRatio_ * (float)h); - else - w = tw_ * h / th_; -} - -void Thumbnail::getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h) { - MyMutex::MyLock lock(mutex); - - // WARNING: When downscaled, the ratio have loosed a lot of precision, so we can't get back the exact initial dimensions - double fw = lastW*lastScale; - double fh = lastH*lastScale; - - if (pparams.coarse.rotate==90 || pparams.coarse.rotate==270) { - fh = lastW*lastScale; - fw = lastH*lastScale; - } - if (!pparams.resize.enabled) { - w = fw; - h = fh; - } - else { - w = (int)(fw+0.5); - h = (int)(fh+0.5); - } -} - - -rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) { - - MyMutex::MyLock lock(mutex); - - if ( tpp == 0 ) { - _loadThumbnail(); - if ( tpp == 0 ) - return 0; - } - - rtengine::IImage8* image = 0; - - if ( cfs.thumbImgType == CacheImageData::QUICK_THUMBNAIL ) { - // RAW internal thumbnail, no profile yet: just do some rotation etc. - image = tpp->quickProcessImage (pparams, h, rtengine::TI_Nearest, scale); - } - else { - // Full thumbnail: apply profile - image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.getCamera(), cfs.focalLen, cfs.focalLen35mm, cfs.focusDist, cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale ); - } - - tpp->getDimensions(lastW,lastH,lastScale); - - delete tpp; - tpp = 0; - return image; -} - -rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) { - - MyMutex::MyLock lock(mutex); - - if ( cfs.thumbImgType != CacheImageData::QUICK_THUMBNAIL ) - { - return 0; - } - - _generateThumbnailImage(); - if ( tpp == 0 ) - { - return 0; - } - - rtengine::IImage8* image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.getCamera(), cfs.focalLen, cfs.focalLen35mm, cfs.focusDist,cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale ); - tpp->getDimensions(lastW,lastH,lastScale); - - delete tpp; - tpp = 0; - return image; -} - -void Thumbnail::generateExifDateTimeStrings () { - - exifString = ""; - dateTimeString = ""; - - if (!cfs.exifValid) - return; - - exifString = Glib::ustring::compose ("f/%1 %2s %3%4 %5mm", Glib::ustring(rtengine::ImageData::apertureToString(cfs.fnumber)), Glib::ustring(rtengine::ImageData::shutterToString(cfs.shutter)), M("QINFO_ISO"), cfs.iso, Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), cfs.focalLen)); - - if (options.fbShowExpComp && cfs.expcomp!="0.00" && cfs.expcomp!="") // don't show exposure compensation if it is 0.00EV;old cache iles do not have ExpComp, so value will not be displayed. - exifString = Glib::ustring::compose ("%1 %2EV", exifString, cfs.expcomp); // append exposure compensation to exifString - std::string dateFormat = options.dateFormat; - std::ostringstream ostr; - bool spec = false; - for (size_t i=0; ihasExif()) { - cfs.shutter = idata->getShutterSpeed (); - cfs.fnumber = idata->getFNumber (); - cfs.focalLen = idata->getFocalLen (); - cfs.focalLen35mm = idata->getFocalLen35mm (); - cfs.focusDist = idata->getFocusDist (); - cfs.iso = idata->getISOSpeed (); - cfs.expcomp = idata->expcompToString (idata->getExpComp(), false); // do not mask Zero expcomp - cfs.year = 1900 + idata->getDateTime().tm_year; - cfs.month = idata->getDateTime().tm_mon + 1; - cfs.day = idata->getDateTime().tm_mday; - cfs.hour = idata->getDateTime().tm_hour; - cfs.min = idata->getDateTime().tm_min; - cfs.sec = idata->getDateTime().tm_sec; - cfs.timeValid = true; - cfs.exifValid = true; - cfs.lens = idata->getLens(); - cfs.camMake = idata->getMake(); - cfs.camModel = idata->getModel(); - - if (idata->getOrientation()=="Rotate 90 CW") { - deg = 90; - } - else if (idata->getOrientation()=="Rotate 180") { - deg = 180; - } - else if (idata->getOrientation()=="Rotate 270 CW") { - deg = 270; - } - } - else { - cfs.lens = "Unknown"; - cfs.camMake = "Unknown"; - cfs.camModel = "Unknown"; - } - // get image filetype - std::string::size_type idx; - idx = fname.rfind('.'); - if(idx != std::string::npos){cfs.filetype = fname.substr(idx+1);} - else {cfs.filetype="";} - - delete idata; - return deg; -} - -/* - * Read all thumbnail's data from the cache; build and save them if doesn't exist - NON PROTECTED - * This includes: - * - image's bitmap (*.rtti) - * - auto exposure's histogram (full thumbnail only) - * - embedded profile (full thumbnail only) - * - LiveThumbData section of the data file - */ -void Thumbnail::_loadThumbnail(bool firstTrial) { - - needsReProcessing = true; - tw = -1; - th = options.maxThumbnailHeight; - delete tpp; - tpp = new rtengine::Thumbnail (); - tpp->isRaw = (cfs.format == (int) FT_Raw); - - // load supplementary data - bool succ = tpp->readData (getCacheFileName ("data")+".txt"); - - if (succ) - tpp->getAutoWBMultipliers(cfs.redAWBMul, cfs.greenAWBMul, cfs.blueAWBMul); - - // thumbnail image - succ = succ && tpp->readImage (getCacheFileName ("images")); - - if (!succ && firstTrial) { - _generateThumbnailImage (); - if (cfs.supported && firstTrial) - _loadThumbnail (false); - - if (tpp==NULL) return; - } - else if (!succ) { - delete tpp; - tpp = NULL; - return; - } - - if ( cfs.thumbImgType == CacheImageData::FULL_THUMBNAIL ) { - // load aehistogram - tpp->readAEHistogram (getCacheFileName ("aehistograms")); - - // load embedded profile - tpp->readEmbProfile (getCacheFileName ("embprofiles")+".icc"); - - tpp->init (); - } - - if (!initial_ && tpp) tw = tpp->getImageWidth (getProcParamsU(), th, imgRatio); // this might return 0 if image was just building -} - -/* - * Read all thumbnail's data from the cache; build and save them if doesn't exist - MUTEX PROTECTED - * This includes: - * - image's bitmap (*.rtti) - * - auto exposure's histogram (full thumbnail only) - * - embedded profile (full thumbnail only) - * - LiveThumbData section of the data file - */ -void Thumbnail::loadThumbnail (bool firstTrial) { - MyMutex::MyLock lock(mutex); - _loadThumbnail(firstTrial); -} - -/* - * Save thumbnail's data to the cache - NON PROTECTED - * This includes: - * - image's bitmap (*.rtti) - * - auto exposure's histogram (full thumbnail only) - * - embedded profile (full thumbnail only) - * - LiveThumbData section of the data file - */ -void Thumbnail::_saveThumbnail () { - - if (!tpp) - return; - - if (safe_g_remove (getCacheFileName ("images")+".rtti") == -1) { - // No file deleted, so we try to deleted obsolete files, if any - safe_g_remove (getCacheFileName ("images")+".cust"); - safe_g_remove (getCacheFileName ("images")+".cust16"); - safe_g_remove (getCacheFileName ("images")+".jpg"); - } - - // save thumbnail image - tpp->writeImage (getCacheFileName ("images"), 1); - - // save aehistogram - tpp->writeAEHistogram (getCacheFileName ("aehistograms")); - - // save embedded profile - tpp->writeEmbProfile (getCacheFileName ("embprofiles")+".icc"); - - // save supplementary data - tpp->writeData (getCacheFileName ("data")+".txt"); -} - -/* - * Save thumbnail's data to the cache - MUTEX PROTECTED - * This includes: - * - image's bitmap (*.rtti) - * - auto exposure's histogram (full thumbnail only) - * - embedded profile (full thumbnail only) - * - LiveThumbData section of the data file - */ -void Thumbnail::saveThumbnail () -{ - MyMutex::MyLock lock(mutex); - _saveThumbnail(); -} - -/* - * Update the cached files - * - updatePParams==true (default) : write the procparams file (sidecar or cache, depending on the options) - * - updateCacheImageData==true (default) : write the CacheImageData values in the cache folder, - * i.e. some General, DateTime, ExifInfo, File info and ExtraRawInfo, - */ -void Thumbnail::updateCache (bool updatePParams, bool updateCacheImageData) { - - if (updatePParams && pparamsValid) { - pparams.save ( - options.saveParamsFile ? fname + paramFileExtension : "", - options.saveParamsCache ? getCacheFileName ("profiles")+paramFileExtension : "", - true - ); - } - if (updateCacheImageData) - cfs.save (getCacheFileName ("data")+".txt"); -} - -Thumbnail::~Thumbnail () { - mutex.lock(); - - delete [] lastImg; - delete tpp; - mutex.unlock(); -} - -Glib::ustring Thumbnail::getCacheFileName (Glib::ustring subdir) { - - return cachemgr->getCacheFileName (subdir, fname, cfs.md5); -} - -void Thumbnail::setFileName (const Glib::ustring fn) { - - fname = fn; - cfs.md5 = cachemgr->getMD5 (fname); -} - -void Thumbnail::addThumbnailListener (ThumbnailListener* tnl) { - - increaseRef(); - listeners.push_back (tnl); -} - -void Thumbnail::removeThumbnailListener (ThumbnailListener* tnl) { - - std::vector::iterator f = std::find (listeners.begin(), listeners.end(), tnl); - if (f!=listeners.end()) { - listeners.erase (f); - decreaseRef(); - } -} - -// Calculates the standard filename for the automatically named batch result -// and opens it in OS default viewer -// destination: 1=Batch conf. file; 2=batch out dir; 3=RAW dir -// Return: Success? -bool Thumbnail::openDefaultViewer(int destination) { - -#ifdef WIN32 - Glib::ustring openFName; - - if (destination==1) { - openFName = Glib::ustring::compose ("%1.%2", BatchQueue::calcAutoFileNameBase(fname), options.saveFormatBatch.format); - if (safe_file_test (openFName, Glib::FILE_TEST_EXISTS)) { - wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (openFName.c_str(), -1, NULL, NULL, NULL); - ShellExecuteW(NULL, L"open", wfilename, NULL, NULL, SW_SHOWMAXIMIZED ); - g_free(wfilename); - } else { - printf("%s not found\n",openFName.data()); - return false; - } - } else { - openFName = destination == 3 ? fname - : Glib::ustring::compose ("%1.%2", BatchQueue::calcAutoFileNameBase(fname), options.saveFormatBatch.format); - - printf("Opening %s\n", openFName.c_str()); - - if (safe_file_test (openFName, Glib::FILE_TEST_EXISTS)) { - // Output file exists, so open explorer and select output file - wchar_t* org=(wchar_t*)g_utf8_to_utf16 (Glib::ustring::compose("/select,\"%1\"", openFName).c_str(), -1, NULL, NULL, NULL); - wchar_t* par=new wchar_t[wcslen(org)+1]; - wcscpy(par, org); - - // In this case the / disturbs - wchar_t* p = par+1; // skip the first backslash - while (*p!=0) { - if (*p==L'/') *p=L'\\'; - p++; - } - - ShellExecuteW(NULL, L"open", L"explorer.exe", par, NULL, SW_SHOWNORMAL ); - - delete[] par; - g_free(org); - } else if (safe_file_test (Glib::path_get_dirname(openFName), Glib::FILE_TEST_EXISTS)) { - // Out file does not exist, but directory - wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (Glib::path_get_dirname(openFName).c_str(), -1, NULL, NULL, NULL); - ShellExecuteW(NULL, L"explore", wfilename, NULL, NULL, SW_SHOWNORMAL ); - g_free(wfilename); - } else { - printf("File and dir not found\n"); - return false; - } - } - - return true; - -#else - // TODO: Add more OSes here - printf("Automatic opening not supported on this OS\n"); - return false; -#endif - -} - -bool Thumbnail::imageLoad(bool loading) -{ - MyMutex::MyLock lock(mutex); - bool previous = imageLoading; - if( loading && !previous ){ - imageLoading = true; - return true; - }else if( !loading ) - imageLoading = false; - return false; -} +/* + * This file is part of RawTherapee. + * + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "multilangmgr.h" +#include "thumbnail.h" +#include +#include +#include "options.h" +#include "../rtengine/mytime.h" +#include +#include +#include +#include "../rtengine/imagedata.h" +#include +#include "guiutils.h" +#include "profilestore.h" +#include "batchqueue.h" +#include "../rtengine/safegtk.h" + +using namespace rtengine::procparams; + +Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) + : fname(fname), cfs(*cf), cachemgr(cm), ref(1), enqueueNumber(0), tpp(NULL), + pparamsValid(false), needsReProcessing(true),imageLoading(false), lastImg(NULL), + lastW(0), lastH(0), lastScale(0), initial_(false) +{ + + loadProcParams (); + + // should be safe to use the unprotected version of loadThumbnail, since we are in the constructor + _loadThumbnail (); + generateExifDateTimeStrings (); + + if (cfs.rankOld >= 0){ + // rank and inTrash were found in cache (old style), move them over to pparams + + // try to load the last saved parameters from the cache or from the paramfile file + createProcParamsForUpdate(false, false); // this can execute customprofilebuilder to generate param file + + // TODO? should we call notifylisterners_procParamsChanged here? + + setRank(cfs.rankOld); + setStage(cfs.inTrashOld); + } + + delete tpp; + tpp = 0; +} + +Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5) + : fname(fname), cachemgr(cm), ref(1), enqueueNumber(0), tpp(NULL), pparamsValid(false), + needsReProcessing(true),imageLoading(false), lastImg(NULL), + initial_(true) +{ + + + cfs.md5 = md5; + loadProcParams (); + _generateThumbnailImage (); + cfs.recentlySaved = false; + + initial_ = false; + + delete tpp; + tpp = 0; +} + +void Thumbnail::_generateThumbnailImage () { + + // delete everything loaded into memory + delete tpp; + tpp = NULL; + delete [] lastImg; + lastImg = NULL; + tw = -1; + th = options.maxThumbnailHeight; + imgRatio = -1.; + + // generate thumbnail image + Glib::ustring ext = getExtension (fname); + if (ext=="") + return; + cfs.supported = false; + cfs.exifValid = false; + cfs.timeValid = false; + + if (ext.lowercase()=="jpg" || ext.lowercase()=="jpeg") { + infoFromImage (fname); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams.wb.equal); + if (tpp) + cfs.format = FT_Jpeg; + } + else if (ext.lowercase()=="png") { + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams.wb.equal); + if (tpp) + cfs.format = FT_Png; + } + else if (ext.lowercase()=="tif" || ext.lowercase()=="tiff") { + infoFromImage (fname); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams.wb.equal); + if (tpp) + cfs.format = FT_Tiff; + } + else { + // RAW works like this: + // 1. if we are here it's because we aren't in the cache so load the JPG + // image out of the RAW. Mark as "quick". + // 2. if we don't find that then just grab the real image. + bool quick = false; + rtengine::RawMetaDataLocation ri; + if ( initial_ && options.internalThumbIfUntouched) + { + quick = true; + tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, tw, th, 1, TRUE); + } + if ( tpp == NULL ) + { + quick = false; + tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1, pparams.wb.equal, TRUE); + } + if (tpp) { + cfs.format = FT_Raw; + cfs.thumbImgType = quick ? CacheImageData::QUICK_THUMBNAIL : CacheImageData::FULL_THUMBNAIL; + infoFromImage (fname, &ri); + } + } + + if (tpp) + { + tpp->getAutoWBMultipliers(cfs.redAWBMul, cfs.greenAWBMul, cfs.blueAWBMul); + _saveThumbnail (); + cfs.supported = true; + needsReProcessing = true; + + cfs.save (getCacheFileName ("data")+".txt"); + + generateExifDateTimeStrings (); + } +} + +bool Thumbnail::isSupported () { + return cfs.supported; +} + +const ProcParams& Thumbnail::getProcParams () { + MyMutex::MyLock lock(mutex); + return getProcParamsU(); +} + +// Unprotected version of getProcParams, when +const ProcParams& Thumbnail::getProcParamsU () { + if (pparamsValid) + return pparams; + else { + pparams = *(profileStore.getDefaultProcParams (getType()==FT_Raw)); + if (pparams.wb.method=="Camera") { + double ct; + getCamWB (ct, pparams.wb.green); + pparams.wb.temperature = ct; + } + else if (pparams.wb.method=="Auto") { + double ct; + getAutoWB (ct, pparams.wb.green, pparams.wb.equal); + pparams.wb.temperature = ct; + } + } + return pparams; // there is no valid pp to return, but we have to return something +} + +/** @brief Create default params on demand and returns a new updatable object + * + * The loaded profile may be partial, but it return a complete ProcParams (i.e. without ParamsEdited) + * + * @param returnParams Ask to return a pointer to a ProcParams object if true + * @param forceCPB True if the Custom Profile Builder has to be invoked, False if the CPB has to be invoked if the profile doesn't + * exist yet. It depends on other conditions too + * @param flaggingMode True if the ProcParams will be created because the file browser is being flagging an image + * (rang, to trash, color labels). This parameter is passed to the CPB. + * + * @return Return a pointer to a ProcPamas structure to be updated if returnParams is true and if everything went fine, NULL otherwise. + */ +rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool returnParams, bool forceCPB, bool flaggingMode) { + + static int index=0; // Will act as unique identifier during the session + + // try to load the last saved parameters from the cache or from the paramfile file + ProcParams* ldprof = NULL; + + Glib::ustring defProf = getType()==FT_Raw ? options.defProfRaw : options.defProfImg; + + const CacheImageData* cfs=getCacheImageData(); + Glib::ustring defaultPparamsPath = options.findProfilePath(defProf); + if (!options.CPBPath.empty() && !defaultPparamsPath.empty() && (!hasProcParams() || forceCPB) && cfs && cfs->exifValid) { + // First generate the communication file, with general values and EXIF metadata + rtengine::ImageMetaData* imageMetaData; + if (getType()==FT_Raw) { + rtengine::RawMetaDataLocation metaData = rtengine::Thumbnail::loadMetaDataFromRaw(fname); + imageMetaData = rtengine::ImageMetaData::fromFile (fname, &metaData); + } + else + imageMetaData = rtengine::ImageMetaData::fromFile (fname, NULL); + + Glib::ustring tmpFileName( Glib::build_filename(options.cacheBaseDir, Glib::ustring::compose("CPB_temp_%1.txt", index++)) ); + + const rtexif::TagDirectory* exifDir=NULL; + if (imageMetaData && (exifDir = imageMetaData->getExifData())) { + Glib::ustring outFName; + if (options.paramsLoadLocation==PLL_Input) + outFName = fname+paramFileExtension; + else + outFName = getCacheFileName("profiles")+paramFileExtension; + exifDir->CPBDump(tmpFileName, fname, outFName, + defaultPparamsPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(defaultPparamsPath, Glib::path_get_basename(defProf) + paramFileExtension), + cfs, + flaggingMode); + } + + // For the filename etc. do NOT use streams, since they are not UTF8 safe + Glib::ustring cmdLine = options.CPBPath + Glib::ustring(" \"") + tmpFileName + Glib::ustring("\""); + + if (options.rtSettings.verbose) + printf("Custom profile builder's command line: %s\n", Glib::ustring(cmdLine).c_str()); + bool success = safe_spawn_command_line_sync (cmdLine); + + // Now they SHOULD be there (and potentially "partial"), so try to load them and store it as a full procparam + if (success) loadProcParams(); + + if (safe_file_test(tmpFileName, Glib::FILE_TEST_EXISTS )) safe_g_remove (tmpFileName); + + if (imageMetaData) delete imageMetaData; + } + + if (returnParams && hasProcParams()) { + ldprof = new ProcParams (); + *ldprof = getProcParams (); + } + + return ldprof; +} + +void Thumbnail::notifylisterners_procParamsChanged(int whoChangedIt){ + for (size_t i=0; iprocParamsChanged (this, whoChangedIt); +} + +/* + * Load the procparams from the cache or from the sidecar file (priority set in + * the Preferences). + * + * The result is a complete ProcParams with default values merged with the values + * from the default Raw or Image ProcParams, then with the values from the loaded + * ProcParams (sidecar or cache file). + */ +void Thumbnail::loadProcParams () { + MyMutex::MyLock lock(mutex); + + pparamsValid = false; + pparams.setDefaults(); + const PartialProfile *defaultPP = profileStore.getDefaultPartialProfile(getType()==FT_Raw); + defaultPP->applyTo(&pparams); + + if (options.paramsLoadLocation==PLL_Input) { + // try to load it from params file next to the image file + int ppres = pparams.load (fname + paramFileExtension); + pparamsValid = !ppres && pparams.ppVersion>=220; + // if no success, try to load the cached version of the procparams + if (!pparamsValid) + pparamsValid = !pparams.load (getCacheFileName ("profiles")+paramFileExtension); + } + else { + // try to load it from cache + pparamsValid = !pparams.load (getCacheFileName ("profiles")+paramFileExtension); + // if no success, try to load it from params file next to the image file + if (!pparamsValid) { + int ppres = pparams.load (fname + paramFileExtension); + pparamsValid = !ppres && pparams.ppVersion>=220; + } + } +} + +void Thumbnail::clearProcParams (int whoClearedIt) { + +/* Clarification on current "clear profile" functionality: + a. if rank/colorlabel/inTrash are NOT set, + the "clear profile" will delete the pp3 file (as before). + + b. if any of the rank/colorlabel/inTrash ARE set, + the "clear profile" will lead to execution of ProcParams::setDefaults + (the CPB is NOT called) to set the params values and will preserve + rank/colorlabel/inTrash in the param file. */ + + { + MyMutex::MyLock lock(mutex); + + // preserve rank, colorlabel and inTrash across clear + int rank = getRank(); + int colorlabel = getColorLabel(); + int inTrash = getStage(); + + + cfs.recentlySaved = false; + pparamsValid = false; + needsReProcessing = true; + + //TODO: run though customprofilebuilder? + // probably not as this is the only option to set param values to default + + // reset the params to defaults + pparams.setDefaults(); + + // and restore rank and inTrash + setRank(rank); + setColorLabel(colorlabel); + setStage(inTrash); + + // params could get validated by rank/inTrash values restored above + if (pparamsValid) + { + updateCache(); + } + else + { + // remove param file from cache + Glib::ustring fname_ = getCacheFileName ("profiles")+paramFileExtension; + if (safe_file_test (fname_, Glib::FILE_TEST_EXISTS)) + safe_g_remove (fname_); + // remove param file located next to the file +// fname_ = removeExtension(fname) + paramFileExtension; + fname_ = fname + paramFileExtension; + if (safe_file_test(fname_, Glib::FILE_TEST_EXISTS)) + safe_g_remove (fname_); + fname_ = removeExtension(fname) + paramFileExtension; + if (safe_file_test (fname_, Glib::FILE_TEST_EXISTS)) + safe_g_remove (fname_); + + if (cfs.format == FT_Raw && options.internalThumbIfUntouched && cfs.thumbImgType != CacheImageData::QUICK_THUMBNAIL) { + // regenerate thumbnail, ie load the quick thumb again. For the rare formats not supporting quick thumbs this will + // be a bit slow as a new full thumbnail will be generated unnecessarily, but currently there is no way to pre-check + // if the format supports quick thumbs. + initial_ = true; + _generateThumbnailImage(); + initial_ = false; + } + } + + } // end of mutex lock + + for (size_t i=0; iprocParamsChanged (this, whoClearedIt); +} + +bool Thumbnail::hasProcParams () { + + return pparamsValid; +} + +void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoChangedIt, bool updateCacheNow) { + + { + MyMutex::MyLock lock(mutex); + + if (pparams.sharpening.threshold.isDouble() != pp.sharpening.threshold.isDouble()) + printf("WARNING: Sharpening different!\n"); + if (pparams.vibrance.psthreshold.isDouble() != pp.vibrance.psthreshold.isDouble()) + printf("WARNING: Vibrance different!\n"); + + if (pparams!=pp) + cfs.recentlySaved = false; + + // do not update rank, colorlabel and inTrash + int rank = getRank(); + int colorlabel = getColorLabel(); + int inTrash = getStage(); + + if (pe) { + pe->combine(pparams, pp, true); + } + else pparams = pp; + pparamsValid = true; + needsReProcessing = true; + + setRank(rank); + setColorLabel(colorlabel); + setStage(inTrash); + + if (updateCacheNow) + updateCache (); + + } // end of mutex lock + + for (size_t i=0; iprocParamsChanged (this, whoChangedIt); +} + +bool Thumbnail::isRecentlySaved () { + + return cfs.recentlySaved; +} + +void Thumbnail::imageDeveloped () { + + cfs.recentlySaved = true; + cfs.save (getCacheFileName ("data")+".txt"); + if (options.saveParamsCache) + pparams.save (getCacheFileName ("profiles")+paramFileExtension); +} + +void Thumbnail::imageEnqueued () { + + enqueueNumber++; +} + +void Thumbnail::imageRemovedFromQueue () { + + enqueueNumber--; +} + +bool Thumbnail::isEnqueued () { + + return enqueueNumber > 0; +} + +void Thumbnail::increaseRef () +{ + MyMutex::MyLock lock(mutex); + ++ref; +} + +void Thumbnail::decreaseRef () +{ + { + MyMutex::MyLock lock(mutex); + if ( ref == 0 ) + { + return; + } + if ( --ref != 0 ) + { + return; + } + } + cachemgr->closeThumbnail (this); +} + +void Thumbnail::getThumbnailSize (int &w, int &h, const rtengine::procparams::ProcParams *pparams) { + int tw_ = tw; + int th_ = th; + float imgRatio_ = imgRatio; + + if (pparams) { + int ppCoarse = pparams->coarse.rotate; + if (ppCoarse >= 180) ppCoarse -= 180; + + int thisCoarse = this->pparams.coarse.rotate; + if (thisCoarse >= 180) thisCoarse -= 180; + + if (thisCoarse != ppCoarse) { + // different orientation -> swapping width & height + int tmp = th_; + th_ = tw_; + tw_ = tmp; + if (imgRatio_ >= 0.0001f) + imgRatio_ = 1.f/imgRatio_; + } + } + + if (imgRatio_ > 0.) + w = (int)(imgRatio_ * (float)h); + else + w = tw_ * h / th_; +} + +void Thumbnail::getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h) { + MyMutex::MyLock lock(mutex); + + // WARNING: When downscaled, the ratio have loosed a lot of precision, so we can't get back the exact initial dimensions + double fw = lastW*lastScale; + double fh = lastH*lastScale; + + if (pparams.coarse.rotate==90 || pparams.coarse.rotate==270) { + fh = lastW*lastScale; + fw = lastH*lastScale; + } + if (!pparams.resize.enabled) { + w = fw; + h = fh; + } + else { + w = (int)(fw+0.5); + h = (int)(fh+0.5); + } +} + + +rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) { + + MyMutex::MyLock lock(mutex); + + if ( tpp == 0 ) { + _loadThumbnail(); + if ( tpp == 0 ) + return 0; + } + + rtengine::IImage8* image = 0; + + if ( cfs.thumbImgType == CacheImageData::QUICK_THUMBNAIL ) { + // RAW internal thumbnail, no profile yet: just do some rotation etc. + image = tpp->quickProcessImage (pparams, h, rtengine::TI_Nearest, scale); + } + else { + // Full thumbnail: apply profile + image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.getCamera(), cfs.focalLen, cfs.focalLen35mm, cfs.focusDist, cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale ); + } + + tpp->getDimensions(lastW,lastH,lastScale); + + delete tpp; + tpp = 0; + return image; +} + +rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) { + + MyMutex::MyLock lock(mutex); + + if ( cfs.thumbImgType != CacheImageData::QUICK_THUMBNAIL ) + { + return 0; + } + + _generateThumbnailImage(); + if ( tpp == 0 ) + { + return 0; + } + + rtengine::IImage8* image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.getCamera(), cfs.focalLen, cfs.focalLen35mm, cfs.focusDist,cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale ); + tpp->getDimensions(lastW,lastH,lastScale); + + delete tpp; + tpp = 0; + return image; +} + +void Thumbnail::generateExifDateTimeStrings () { + + exifString = ""; + dateTimeString = ""; + + if (!cfs.exifValid) + return; + + exifString = Glib::ustring::compose ("f/%1 %2s %3%4 %5mm", Glib::ustring(rtengine::ImageData::apertureToString(cfs.fnumber)), Glib::ustring(rtengine::ImageData::shutterToString(cfs.shutter)), M("QINFO_ISO"), cfs.iso, Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), cfs.focalLen)); + + if (options.fbShowExpComp && cfs.expcomp!="0.00" && cfs.expcomp!="") // don't show exposure compensation if it is 0.00EV;old cache iles do not have ExpComp, so value will not be displayed. + exifString = Glib::ustring::compose ("%1 %2EV", exifString, cfs.expcomp); // append exposure compensation to exifString + std::string dateFormat = options.dateFormat; + std::ostringstream ostr; + bool spec = false; + for (size_t i=0; ihasExif()) { + cfs.shutter = idata->getShutterSpeed (); + cfs.fnumber = idata->getFNumber (); + cfs.focalLen = idata->getFocalLen (); + cfs.focalLen35mm = idata->getFocalLen35mm (); + cfs.focusDist = idata->getFocusDist (); + cfs.iso = idata->getISOSpeed (); + cfs.expcomp = idata->expcompToString (idata->getExpComp(), false); // do not mask Zero expcomp + cfs.year = 1900 + idata->getDateTime().tm_year; + cfs.month = idata->getDateTime().tm_mon + 1; + cfs.day = idata->getDateTime().tm_mday; + cfs.hour = idata->getDateTime().tm_hour; + cfs.min = idata->getDateTime().tm_min; + cfs.sec = idata->getDateTime().tm_sec; + cfs.timeValid = true; + cfs.exifValid = true; + cfs.lens = idata->getLens(); + cfs.camMake = idata->getMake(); + cfs.camModel = idata->getModel(); + + if (idata->getOrientation()=="Rotate 90 CW") { + deg = 90; + } + else if (idata->getOrientation()=="Rotate 180") { + deg = 180; + } + else if (idata->getOrientation()=="Rotate 270 CW") { + deg = 270; + } + } + else { + cfs.lens = "Unknown"; + cfs.camMake = "Unknown"; + cfs.camModel = "Unknown"; + } + // get image filetype + std::string::size_type idx; + idx = fname.rfind('.'); + if(idx != std::string::npos){cfs.filetype = fname.substr(idx+1);} + else {cfs.filetype="";} + + delete idata; + return deg; +} + +/* + * Read all thumbnail's data from the cache; build and save them if doesn't exist - NON PROTECTED + * This includes: + * - image's bitmap (*.rtti) + * - auto exposure's histogram (full thumbnail only) + * - embedded profile (full thumbnail only) + * - LiveThumbData section of the data file + */ +void Thumbnail::_loadThumbnail(bool firstTrial) { + + needsReProcessing = true; + tw = -1; + th = options.maxThumbnailHeight; + delete tpp; + tpp = new rtengine::Thumbnail (); + tpp->isRaw = (cfs.format == (int) FT_Raw); + + // load supplementary data + bool succ = tpp->readData (getCacheFileName ("data")+".txt"); + + if (succ) + tpp->getAutoWBMultipliers(cfs.redAWBMul, cfs.greenAWBMul, cfs.blueAWBMul); + + // thumbnail image + succ = succ && tpp->readImage (getCacheFileName ("images")); + + if (!succ && firstTrial) { + _generateThumbnailImage (); + if (cfs.supported && firstTrial) + _loadThumbnail (false); + + if (tpp==NULL) return; + } + else if (!succ) { + delete tpp; + tpp = NULL; + return; + } + + if ( cfs.thumbImgType == CacheImageData::FULL_THUMBNAIL ) { + // load aehistogram + tpp->readAEHistogram (getCacheFileName ("aehistograms")); + + // load embedded profile + tpp->readEmbProfile (getCacheFileName ("embprofiles")+".icc"); + + tpp->init (); + } + + if (!initial_ && tpp) tw = tpp->getImageWidth (getProcParamsU(), th, imgRatio); // this might return 0 if image was just building +} + +/* + * Read all thumbnail's data from the cache; build and save them if doesn't exist - MUTEX PROTECTED + * This includes: + * - image's bitmap (*.rtti) + * - auto exposure's histogram (full thumbnail only) + * - embedded profile (full thumbnail only) + * - LiveThumbData section of the data file + */ +void Thumbnail::loadThumbnail (bool firstTrial) { + MyMutex::MyLock lock(mutex); + _loadThumbnail(firstTrial); +} + +/* + * Save thumbnail's data to the cache - NON PROTECTED + * This includes: + * - image's bitmap (*.rtti) + * - auto exposure's histogram (full thumbnail only) + * - embedded profile (full thumbnail only) + * - LiveThumbData section of the data file + */ +void Thumbnail::_saveThumbnail () { + + if (!tpp) + return; + + if (safe_g_remove (getCacheFileName ("images")+".rtti") == -1) { + // No file deleted, so we try to deleted obsolete files, if any + safe_g_remove (getCacheFileName ("images")+".cust"); + safe_g_remove (getCacheFileName ("images")+".cust16"); + safe_g_remove (getCacheFileName ("images")+".jpg"); + } + + // save thumbnail image + tpp->writeImage (getCacheFileName ("images"), 1); + + // save aehistogram + tpp->writeAEHistogram (getCacheFileName ("aehistograms")); + + // save embedded profile + tpp->writeEmbProfile (getCacheFileName ("embprofiles")+".icc"); + + // save supplementary data + tpp->writeData (getCacheFileName ("data")+".txt"); +} + +/* + * Save thumbnail's data to the cache - MUTEX PROTECTED + * This includes: + * - image's bitmap (*.rtti) + * - auto exposure's histogram (full thumbnail only) + * - embedded profile (full thumbnail only) + * - LiveThumbData section of the data file + */ +void Thumbnail::saveThumbnail () +{ + MyMutex::MyLock lock(mutex); + _saveThumbnail(); +} + +/* + * Update the cached files + * - updatePParams==true (default) : write the procparams file (sidecar or cache, depending on the options) + * - updateCacheImageData==true (default) : write the CacheImageData values in the cache folder, + * i.e. some General, DateTime, ExifInfo, File info and ExtraRawInfo, + */ +void Thumbnail::updateCache (bool updatePParams, bool updateCacheImageData) { + + if (updatePParams && pparamsValid) { + pparams.save ( + options.saveParamsFile ? fname + paramFileExtension : "", + options.saveParamsCache ? getCacheFileName ("profiles")+paramFileExtension : "", + true + ); + } + if (updateCacheImageData) + cfs.save (getCacheFileName ("data")+".txt"); +} + +Thumbnail::~Thumbnail () { + mutex.lock(); + + delete [] lastImg; + delete tpp; + mutex.unlock(); +} + +Glib::ustring Thumbnail::getCacheFileName (Glib::ustring subdir) { + + return cachemgr->getCacheFileName (subdir, fname, cfs.md5); +} + +void Thumbnail::setFileName (const Glib::ustring fn) { + + fname = fn; + cfs.md5 = cachemgr->getMD5 (fname); +} + +void Thumbnail::addThumbnailListener (ThumbnailListener* tnl) { + + increaseRef(); + listeners.push_back (tnl); +} + +void Thumbnail::removeThumbnailListener (ThumbnailListener* tnl) { + + std::vector::iterator f = std::find (listeners.begin(), listeners.end(), tnl); + if (f!=listeners.end()) { + listeners.erase (f); + decreaseRef(); + } +} + +// Calculates the standard filename for the automatically named batch result +// and opens it in OS default viewer +// destination: 1=Batch conf. file; 2=batch out dir; 3=RAW dir +// Return: Success? +bool Thumbnail::openDefaultViewer(int destination) { + +#ifdef WIN32 + Glib::ustring openFName; + + if (destination==1) { + openFName = Glib::ustring::compose ("%1.%2", BatchQueue::calcAutoFileNameBase(fname), options.saveFormatBatch.format); + if (safe_file_test (openFName, Glib::FILE_TEST_EXISTS)) { + wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (openFName.c_str(), -1, NULL, NULL, NULL); + ShellExecuteW(NULL, L"open", wfilename, NULL, NULL, SW_SHOWMAXIMIZED ); + g_free(wfilename); + } else { + printf("%s not found\n",openFName.data()); + return false; + } + } else { + openFName = destination == 3 ? fname + : Glib::ustring::compose ("%1.%2", BatchQueue::calcAutoFileNameBase(fname), options.saveFormatBatch.format); + + printf("Opening %s\n", openFName.c_str()); + + if (safe_file_test (openFName, Glib::FILE_TEST_EXISTS)) { + // Output file exists, so open explorer and select output file + wchar_t* org=(wchar_t*)g_utf8_to_utf16 (Glib::ustring::compose("/select,\"%1\"", openFName).c_str(), -1, NULL, NULL, NULL); + wchar_t* par=new wchar_t[wcslen(org)+1]; + wcscpy(par, org); + + // In this case the / disturbs + wchar_t* p = par+1; // skip the first backslash + while (*p!=0) { + if (*p==L'/') *p=L'\\'; + p++; + } + + ShellExecuteW(NULL, L"open", L"explorer.exe", par, NULL, SW_SHOWNORMAL ); + + delete[] par; + g_free(org); + } else if (safe_file_test (Glib::path_get_dirname(openFName), Glib::FILE_TEST_EXISTS)) { + // Out file does not exist, but directory + wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (Glib::path_get_dirname(openFName).c_str(), -1, NULL, NULL, NULL); + ShellExecuteW(NULL, L"explore", wfilename, NULL, NULL, SW_SHOWNORMAL ); + g_free(wfilename); + } else { + printf("File and dir not found\n"); + return false; + } + } + + return true; + +#else + // TODO: Add more OSes here + printf("Automatic opening not supported on this OS\n"); + return false; +#endif + +} + +bool Thumbnail::imageLoad(bool loading) +{ + MyMutex::MyLock lock(mutex); + bool previous = imageLoading; + if( loading && !previous ){ + imageLoading = true; + return true; + }else if( !loading ) + imageLoading = false; + return false; +} diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index b2b7a3d46..a4a12ae78 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -1,750 +1,750 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "tonecurve.h" -#include "adjuster.h" -#include -#include -#include "ppversion.h" -#include "edit.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -ToneCurve::ToneCurve () : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LABEL")) { - - CurveListener::setMulti(true); - - std::vector bottomMilestones; - bottomMilestones.push_back( GradientMilestone(0., 0., 0., 0.) ); - bottomMilestones.push_back( GradientMilestone(1., 1., 1., 1.) ); - -//----------- Auto Levels ---------------------------------- - abox = Gtk::manage (new Gtk::HBox ()); - abox->set_border_width (2); - abox->set_spacing (10); - - autolevels = Gtk::manage (new Gtk::ToggleButton (M("TP_EXPOSURE_AUTOLEVELS"))); - autolevels->set_tooltip_markup (M("TP_EXPOSURE_AUTOLEVELS_TIP")); - autoconn = autolevels->signal_toggled().connect( sigc::mem_fun(*this, &ToneCurve::autolevels_toggled) ); - - lclip = Gtk::manage (new Gtk::Label (M("TP_EXPOSURE_CLIP"))); - lclip->set_tooltip_text (M("TP_EXPOSURE_CLIP_TIP")); - - sclip = Gtk::manage (new MySpinButton ()); - sclip->set_range (0.0, 0.99); - sclip->set_increments (0.01, 0.10); - sclip->set_value (0.02); - sclip->set_digits (2); - sclip->signal_value_changed().connect( sigc::mem_fun(*this, &ToneCurve::clip_changed) ); - - neutral = Gtk::manage (new Gtk::Button (M("TP_NEUTRAL"))); - neutral->set_tooltip_text (M("TP_NEUTRAL_TIP")); - neutralconn = neutral->signal_pressed().connect( sigc::mem_fun(*this, &ToneCurve::neutral_pressed) ); - neutral->show(); - - abox->pack_start (*autolevels, true, true, 0); - // pack_end is used for these controls as autolevels is replaceable using pack_start in batchmode - abox->pack_end (*neutral, true, true, 0); - abox->pack_end (*sclip, false, false, 0); - abox->pack_end (*lclip, false, false, 0); - pack_start (*abox); - -//-------------- Highlight Reconstruction ----------------- - pack_start (*Gtk::manage (new Gtk::HSeparator())); - - hrenabled = Gtk::manage (new Gtk::CheckButton (M("TP_HLREC_LABEL"))); - hrenabled->set_active (false); - hrenabled->set_tooltip_markup (M("TP_HLREC_ENA_TOOLTIP")); - pack_start (*hrenabled); - - method = Gtk::manage (new MyComboBoxText ()); - method->append_text (M("TP_HLREC_LUMINANCE")); - method->append_text (M("TP_HLREC_CIELAB")); - method->append_text (M("TP_HLREC_COLOR")); - method->append_text (M("TP_HLREC_BLEND")); - - method->set_active (0); - hlrbox = Gtk::manage (new Gtk::HBox ()); - Gtk::Label* lab = Gtk::manage (new Gtk::Label (M("TP_HLREC_METHOD"))); - hlrbox->pack_start (*lab, Gtk::PACK_SHRINK, 4); - hlrbox->pack_start (*method); - pack_start (*hlrbox); - - enaconn = hrenabled->signal_toggled().connect( sigc::mem_fun(*this, &ToneCurve::hrenabledChanged) ); - methconn = method->signal_changed().connect ( sigc::mem_fun(*this, &ToneCurve::methodChanged) ); - - //----------- Exposure Compensation --------------------- - pack_start (*Gtk::manage (new Gtk::HSeparator())); - - expcomp = Gtk::manage (new Adjuster (M("TP_EXPOSURE_EXPCOMP"), -5, 12, 0.05, 0)); - pack_start (*expcomp); - - //----------- Highlight recovery & threshold ------------- - hlcompr = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRHIGHLIGHTS"), 0, 500, 1, 0)); - pack_start (*hlcompr); - hlcomprthresh = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD"), 0, 100, 1, 33)); - pack_start (*hlcomprthresh); - -//----------- Black Level & Compression ------------------- - black = Gtk::manage (new Adjuster (M("TP_EXPOSURE_BLACKLEVEL"), -16384, 32768, 50, 0)); - pack_start (*black); - shcompr = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRSHADOWS"), 0, 100, 1, 50)); - pack_start (*shcompr); - - pack_start (*Gtk::manage (new Gtk::HSeparator())); - -//---------Brightness / Contrast ------------------------- - brightness = Gtk::manage (new Adjuster (M("TP_EXPOSURE_BRIGHTNESS"), -100, 100, 1, 0)); - pack_start (*brightness); - contrast = Gtk::manage (new Adjuster (M("TP_EXPOSURE_CONTRAST"), -100, 100, 1, 0)); - pack_start (*contrast); - saturation = Gtk::manage (new Adjuster (M("TP_EXPOSURE_SATURATION"), -100, 100, 1, 0)); - pack_start (*saturation); - -//----------- Curve 1 ------------------------------ - pack_start (*Gtk::manage (new Gtk::HSeparator())); - - toneCurveMode = Gtk::manage (new MyComboBoxText ()); - toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_STANDARD")); - toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_WEIGHTEDSTD")); - toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE")); - toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING")); - toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_LUMINANCE")); - toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_PERCEPTUAL")); - toneCurveMode->set_active (0); - toneCurveMode->set_tooltip_text(M("TP_EXPOSURE_TCMODE_LABEL1")); - - curveEditorG = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_EXPOSURE_CURVEEDITOR1")); - curveEditorG->setCurveListener (this); - - shape = static_cast(curveEditorG->addCurve(CT_Diagonal, "", toneCurveMode)); - shape->setEditID(EUID_ToneCurve1, BT_IMAGEFLOAT); - shape->setBottomBarBgGradient(bottomMilestones); - shape->setLeftBarBgGradient(bottomMilestones); - - // This will add the reset button at the end of the curveType buttons - curveEditorG->curveListComplete(); - - pack_start( *curveEditorG, Gtk::PACK_SHRINK, 2); - - tcmodeconn = toneCurveMode->signal_changed().connect( sigc::mem_fun(*this, &ToneCurve::curveMode1Changed), true ); - -//----------- Curve 2 ------------------------------ - - toneCurveMode2 = Gtk::manage (new MyComboBoxText ()); - toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_STANDARD")); - toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_WEIGHTEDSTD")); - toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE")); - toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING")); - toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_LUMINANCE")); - toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_PERCEPTUAL")); - toneCurveMode2->set_active (0); - toneCurveMode2->set_tooltip_text(M("TP_EXPOSURE_TCMODE_LABEL2")); - - curveEditorG2 = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_EXPOSURE_CURVEEDITOR2")); - curveEditorG2->setCurveListener (this); - - shape2 = static_cast(curveEditorG2->addCurve(CT_Diagonal, "", toneCurveMode2)); - shape2->setEditID(EUID_ToneCurve2, BT_IMAGEFLOAT); - shape2->setBottomBarBgGradient(bottomMilestones); - shape2->setLeftBarBgGradient(bottomMilestones); - - // This will add the reset button at the end of the curveType buttons - curveEditorG2->curveListComplete(); - curveEditorG2->setTooltip(M("TP_EXPOSURE_CURVEEDITOR2_TOOLTIP")); - - pack_start( *curveEditorG2, Gtk::PACK_SHRINK, 2); - - tcmode2conn = toneCurveMode2->signal_changed().connect( sigc::mem_fun(*this, &ToneCurve::curveMode2Changed), true ); - -// --------- Set Up Listeners ------------- - expcomp->setAdjusterListener (this); - brightness->setAdjusterListener (this); - black->setAdjusterListener (this); - hlcompr->setAdjusterListener (this); - hlcomprthresh->setAdjusterListener (this); - shcompr->setAdjusterListener (this); - contrast->setAdjusterListener (this); - saturation->setAdjusterListener (this); -} - -ToneCurve::~ToneCurve () { - delete curveEditorG; - delete curveEditorG2; -} - -void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { - - disableListener (); - - tcmodeconn.block(true); - tcmode2conn.block(true); - autoconn.block (true); - - autolevels->set_active (pp->toneCurve.autoexp); - lastAuto = pp->toneCurve.autoexp; - sclip->set_value (pp->toneCurve.clip); - - expcomp->setValue (pp->toneCurve.expcomp); - black->setValue (pp->toneCurve.black); - hlcompr->setValue (pp->toneCurve.hlcompr); - hlcomprthresh->setValue (pp->toneCurve.hlcomprthresh); - shcompr->setValue (pp->toneCurve.shcompr); - if (!black->getAddMode()) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect - brightness->setValue (pp->toneCurve.brightness); - contrast->setValue (pp->toneCurve.contrast); - saturation->setValue (pp->toneCurve.saturation); - shape->setCurve (pp->toneCurve.curve); - shape2->setCurve (pp->toneCurve.curve2); - - toneCurveMode->set_active(pp->toneCurve.curveMode); - toneCurveMode2->set_active(pp->toneCurve.curveMode2); - - if (pedited) { - expcomp->setEditedState (pedited->toneCurve.expcomp ? Edited : UnEdited); - black->setEditedState (pedited->toneCurve.black ? Edited : UnEdited); - hlcompr->setEditedState (pedited->toneCurve.hlcompr ? Edited : UnEdited); - hlcomprthresh->setEditedState (pedited->toneCurve.hlcomprthresh ? Edited : UnEdited); - shcompr->setEditedState (pedited->toneCurve.shcompr ? Edited : UnEdited); - brightness->setEditedState (pedited->toneCurve.brightness ? Edited : UnEdited); - contrast->setEditedState (pedited->toneCurve.contrast ? Edited : UnEdited); - saturation->setEditedState (pedited->toneCurve.saturation ? Edited : UnEdited); - autolevels->set_inconsistent (!pedited->toneCurve.autoexp); - clipDirty = pedited->toneCurve.clip; - shape->setUnChanged (!pedited->toneCurve.curve); - shape2->setUnChanged (!pedited->toneCurve.curve2); - if (!pedited->toneCurve.curveMode) { - toneCurveMode->set_active(6); - } - if (!pedited->toneCurve.curveMode2) { - toneCurveMode2->set_active(6); - } - } - if (pedited) - hrenabled->set_inconsistent (!pedited->toneCurve.hrenabled); - enaconn.block (true); - hrenabled->set_active (pp->toneCurve.hrenabled); - enaconn.block (false); - - if (pedited && !pedited->toneCurve.method) - method->set_active (4); - else if (pp->toneCurve.method=="Luminance") - method->set_active (0); - else if (pp->toneCurve.method=="CIELab blending") - method->set_active (1); - else if (pp->toneCurve.method=="Color") - method->set_active (2); - else if (pp->toneCurve.method=="Blend") - method->set_active (3); - - if (!batchMode) { - if (hrenabled->get_active()) - hlrbox->show(); - else - hlrbox->hide(); - } - lasthrEnabled = pp->toneCurve.hrenabled; - - autoconn.block (false); - tcmode2conn.block(false); - tcmodeconn.block(false); - - enableListener (); -} - -void ToneCurve::autoOpenCurve () { - shape->openIfNonlinear(); - shape2->openIfNonlinear(); -} - -void ToneCurve::setEditProvider (EditDataProvider *provider) { - shape->setEditProvider(provider); - shape2->setEditProvider(provider); -} - -void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) { - - pp->toneCurve.autoexp = autolevels->get_active(); - pp->toneCurve.clip = sclip->get_value (); - pp->toneCurve.expcomp = expcomp->getValue (); - pp->toneCurve.black = (int)black->getValue (); - pp->toneCurve.hlcompr = (int)hlcompr->getValue (); - pp->toneCurve.hlcomprthresh = (int)hlcomprthresh->getValue (); - pp->toneCurve.shcompr = (int)shcompr->getValue (); - pp->toneCurve.brightness = (int)brightness->getValue (); - pp->toneCurve.contrast = (int)contrast->getValue (); - pp->toneCurve.saturation = (int)saturation->getValue (); - pp->toneCurve.curve = shape->getCurve (); - pp->toneCurve.curve2 = shape2->getCurve (); - - int tcMode = toneCurveMode->get_active_row_number(); - if (tcMode == 0) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_STD; - else if (tcMode == 1) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_WEIGHTEDSTD; - else if (tcMode == 2) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_FILMLIKE; - else if (tcMode == 3) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_SATANDVALBLENDING; - else if (tcMode == 4) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_LUMINANCE; - else if (tcMode == 5) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_PERCEPTUAL; - - tcMode = toneCurveMode2->get_active_row_number(); - if (tcMode == 0) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD; - else if (tcMode == 1) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_WEIGHTEDSTD; - else if (tcMode == 2) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_FILMLIKE; - else if (tcMode == 3) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_SATANDVALBLENDING; - else if (tcMode == 4) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_LUMINANCE; - else if (tcMode == 5) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_PERCEPTUAL; - - if (pedited) { - pedited->toneCurve.expcomp = expcomp->getEditedState (); - pedited->toneCurve.black = black->getEditedState (); - pedited->toneCurve.hlcompr = hlcompr->getEditedState (); - pedited->toneCurve.hlcomprthresh = hlcomprthresh->getEditedState (); - pedited->toneCurve.shcompr = shcompr->getEditedState (); - pedited->toneCurve.brightness = brightness->getEditedState (); - pedited->toneCurve.contrast = contrast->getEditedState (); - pedited->toneCurve.saturation = saturation->getEditedState (); - pedited->toneCurve.autoexp = !autolevels->get_inconsistent(); - pedited->toneCurve.clip = clipDirty; - pedited->toneCurve.curve = !shape->isUnChanged (); - pedited->toneCurve.curve2 = !shape2->isUnChanged (); - pedited->toneCurve.curveMode = toneCurveMode->get_active_row_number() != 6; - pedited->toneCurve.curveMode2 = toneCurveMode2->get_active_row_number() != 6; - } - if (pedited) { - pedited->toneCurve.method = method->get_active_row_number()!=4; - pedited->toneCurve.hrenabled = !hrenabled->get_inconsistent(); - } - - pp->toneCurve.hrenabled = hrenabled->get_active(); - if (method->get_active_row_number()==0) - pp->toneCurve.method = "Luminance"; - else if (method->get_active_row_number()==1) - pp->toneCurve.method = "CIELab blending"; - else if (method->get_active_row_number()==2) - pp->toneCurve.method = "Color"; - else if (method->get_active_row_number()==3) - pp->toneCurve.method = "Blend"; -} - -void ToneCurve::hrenabledChanged () { - - if (multiImage) { - if (hrenabled->get_inconsistent()) { - hrenabled->set_inconsistent (false); - enaconn.block (true); - hrenabled->set_active (false); - enaconn.block (false); - } - else if (lasthrEnabled) - hrenabled->set_inconsistent (true); - - lasthrEnabled = hrenabled->get_active (); - } - - if (!batchMode) { - if (hrenabled->get_active()) - hlrbox->show(); - else - hlrbox->hide(); - } - - if (listener) { - // Switch off auto exposure if user changes enabled manually - if (autolevels->get_active() ) { - autoconn.block(true); - autolevels->set_active (false); - autoconn.block(false); - autolevels->set_inconsistent (false); - } - if (hrenabled->get_active ()) - listener->panelChanged (EvHREnabled, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvHREnabled, M("GENERAL_DISABLED")); - } -} -void ToneCurve::methodChanged () { - - if (listener) { - if (hrenabled->get_active ()) - listener->panelChanged (EvHRMethod, method->get_active_text ()); - } -} -void ToneCurve::setRaw (bool raw) { - - disableListener (); - method->set_sensitive (raw); - hrenabled->set_sensitive (raw); - enableListener (); -} - - -void ToneCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - - expcomp->setDefault (defParams->toneCurve.expcomp); - brightness->setDefault (defParams->toneCurve.brightness); - black->setDefault (defParams->toneCurve.black); - hlcompr->setDefault (defParams->toneCurve.hlcompr); - hlcomprthresh->setDefault (defParams->toneCurve.hlcomprthresh); - shcompr->setDefault (defParams->toneCurve.shcompr); - contrast->setDefault (defParams->toneCurve.contrast); - saturation->setDefault (defParams->toneCurve.saturation); - - if (pedited) { - expcomp->setDefaultEditedState (pedited->toneCurve.expcomp ? Edited : UnEdited); - black->setDefaultEditedState (pedited->toneCurve.black ? Edited : UnEdited); - hlcompr->setDefaultEditedState (pedited->toneCurve.hlcompr ? Edited : UnEdited); - hlcomprthresh->setDefaultEditedState (pedited->toneCurve.hlcomprthresh ? Edited : UnEdited); - shcompr->setDefaultEditedState (pedited->toneCurve.shcompr ? Edited : UnEdited); - brightness->setDefaultEditedState (pedited->toneCurve.brightness ? Edited : UnEdited); - contrast->setDefaultEditedState (pedited->toneCurve.contrast ? Edited : UnEdited); - saturation->setDefaultEditedState (pedited->toneCurve.saturation ? Edited : UnEdited); - } - else { - expcomp->setDefaultEditedState (Irrelevant); - black->setDefaultEditedState (Irrelevant); - hlcompr->setDefaultEditedState (Irrelevant); - hlcomprthresh->setDefaultEditedState (Irrelevant); - shcompr->setDefaultEditedState (Irrelevant); - brightness->setDefaultEditedState (Irrelevant); - contrast->setDefaultEditedState (Irrelevant); - saturation->setDefaultEditedState (Irrelevant); - } -} - -void ToneCurve::curveChanged (CurveEditor* ce) { - - if (listener) { - if (ce == shape) - listener->panelChanged (EvToneCurve1, M("HISTORY_CUSTOMCURVE")); - else if (ce == shape2) - listener->panelChanged (EvToneCurve2, M("HISTORY_CUSTOMCURVE")); - } -} - -void ToneCurve::curveMode1Changed () { - //if (listener) listener->panelChanged (EvToneCurveMode, toneCurveMode->get_active_text()); - if (listener) Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::curveMode1Changed_)); -} - -bool ToneCurve::curveMode1Changed_ () { - if (listener) listener->panelChanged (EvToneCurveMode1, toneCurveMode->get_active_text()); - return false; -} - -void ToneCurve::curveMode2Changed () { - //if (listener) listener->panelChanged (EvToneCurveMode, toneCurveMode->get_active_text()); - if (listener) Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::curveMode2Changed_)); -} - -bool ToneCurve::curveMode2Changed_ () { - if (listener) listener->panelChanged (EvToneCurveMode2, toneCurveMode2->get_active_text()); - return false; -} - -float ToneCurve::blendPipetteValues(CurveEditor *ce, float chan1, float chan2, float chan3) { - // assuming that all the channels are used... - if (ce == shape) { - if (toneCurveMode->get_active_row_number() == 4) - return chan1*0.2126729f + chan2*0.7151521f + chan3*0.0721750f; - } - else if (ce == shape2) { - if (toneCurveMode2->get_active_row_number() == 4) - return chan1*0.2126729f + chan2*0.7151521f + chan3*0.0721750f; - } - return CurveListener::blendPipetteValues(ce, chan1, chan2, chan3); -} - -void ToneCurve::adjusterChanged (Adjuster* a, double newval) { - - // Switch off auto exposure if user changes sliders manually - if (autolevels->get_active() && (a==expcomp || a==brightness || a==contrast || a==black || a==hlcompr || a==hlcomprthresh)) { - autoconn.block(true); - autolevels->set_active (false); - autoconn.block(false); - autolevels->set_inconsistent (false); - } - - if (!listener) - return; - - Glib::ustring costr; - if (a==expcomp) - costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), a->getValue()); - else - costr = Glib::ustring::format ((int)a->getValue()); - - if (a==expcomp) - listener->panelChanged (EvExpComp, costr); - else if (a==brightness) - listener->panelChanged (EvBrightness, costr); - else if (a==black){ - listener->panelChanged (EvBlack, costr); - if (!black->getAddMode()) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect - } - else if (a==contrast) - listener->panelChanged (EvContrast, costr); - else if (a==saturation) - listener->panelChanged (EvSaturation, costr); - else if (a==hlcompr) - listener->panelChanged (EvHLCompr, costr); - else if (a==hlcomprthresh) - listener->panelChanged (EvHLComprThreshold, costr); - else if (a==shcompr) - listener->panelChanged (EvSHCompr, costr); -} - -void ToneCurve::neutral_pressed () { -// This method deselects auto levels and HL reconstruction auto -// and sets neutral values to params in exposure panel - - if (batchMode) { - autolevels->set_inconsistent (false); - autoconn.block (true); - autolevels->set_active (false); - autoconn.block (false); - - lastAuto = autolevels->get_active (); - } - else { //!batchMode - autolevels->set_active (false); - autolevels->set_inconsistent (false); - } - - expcomp->setValue(0); - hlcompr->setValue(0); - hlcomprthresh->setValue(0); - brightness->setValue(0); - black->setValue(0); - shcompr->setValue(50); - enaconn.block (true); - hrenabled->set_active (false); - enaconn.block (false); - if (!batchMode) - hlrbox->hide(); - if (!black->getAddMode()) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect - contrast->setValue(0); - //saturation->setValue(0); - - listener->panelChanged (EvNeutralExp, M("GENERAL_ENABLED")); -} -void ToneCurve::autolevels_toggled () { - - if (batchMode) { - if (autolevels->get_inconsistent()) { - autolevels->set_inconsistent (false); - autoconn.block (true); - autolevels->set_active (false); - autoconn.block (false); - } - else if (lastAuto) - autolevels->set_inconsistent (true); - - lastAuto = autolevels->get_active (); - - expcomp->setEditedState (UnEdited); - brightness->setEditedState (UnEdited); - contrast->setEditedState (UnEdited); - black->setEditedState (UnEdited); - hlcompr->setEditedState (UnEdited); - hlcomprthresh->setEditedState (UnEdited); - if (expcomp->getAddMode()) - expcomp->setValue (0); - if (brightness->getAddMode()) - brightness->setValue (0); - if (contrast->getAddMode()) - contrast->setValue (0); - if (black->getAddMode()) - black->setValue (0); - if (hlcompr->getAddMode()) - hlcompr->setValue (0); - if (hlcomprthresh->getAddMode()) - hlcomprthresh->setValue (0); - - if (listener) { - if (!autolevels->get_inconsistent()) { - if (autolevels->get_active ()) - listener->panelChanged (EvAutoExp, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvFixedExp, M("GENERAL_DISABLED")); - } - } - } - else if (/* !batchMode && */ listener) { - if (autolevels->get_active()) { - listener->panelChanged (EvAutoExp, M("GENERAL_ENABLED")); - waitForAutoExp (); - if (!black->getAddMode()) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect - } - else { - listener->panelChanged (EvFixedExp, M("GENERAL_DISABLED")); - } - } -} - -void ToneCurve::clip_changed () { - - clipDirty = true; - if (autolevels->get_active() && listener) - Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::clip_changed_)); -} - -bool ToneCurve::clip_changed_ () { - - if (listener) { - listener->panelChanged (EvClip, Glib::ustring::format (std::setprecision(5), sclip->get_value())); - if (!batchMode) - waitForAutoExp (); - } - return false; -} - -void ToneCurve::waitForAutoExp () { - - sclip->set_sensitive (false); - expcomp->setEnabled (false); - brightness->setEnabled (false); - contrast->setEnabled (false); - black->setEnabled (false); - hlcompr->setEnabled (false); - hlcomprthresh->setEnabled (false); - shcompr->setEnabled (false); - contrast->setEnabled (false); - saturation->setEnabled (false); - curveEditorG->set_sensitive (false); - toneCurveMode->set_sensitive (false); - curveEditorG2->set_sensitive (false); - toneCurveMode2->set_sensitive (false); - hrenabled->set_sensitive(false); - method->set_sensitive(false); -} - -int autoExpChangedUI (void* data) { - (static_cast(data))->autoExpComputed_ (); - return 0; -} - -void ToneCurve::autoExpChanged (double expcomp, int bright, int contr, int black, int hlcompr, int hlcomprthresh, bool hlrecons) { - - nextBlack = black; - nextExpcomp = expcomp; - nextBrightness = bright; - nextContrast = contr; - nextHlcompr = hlcompr; - nextHlcomprthresh = hlcomprthresh; - nextHLRecons = hlrecons; - g_idle_add (autoExpChangedUI, this); -} - -void ToneCurve::enableAll () { - - sclip->set_sensitive (true); - expcomp->setEnabled (true); - brightness->setEnabled (true); - black->setEnabled (true); - hlcompr->setEnabled (true); - hlcomprthresh->setEnabled (true); - shcompr->setEnabled (true); - contrast->setEnabled (true); - saturation->setEnabled (true); - curveEditorG->set_sensitive (true); - toneCurveMode->set_sensitive (true); - curveEditorG2->set_sensitive (true); - toneCurveMode2->set_sensitive (true); - hrenabled->set_sensitive(true); - method->set_sensitive(true); -} - -bool ToneCurve::autoExpComputed_ () { - - GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected - disableListener (); - enableAll (); - expcomp->setValue (nextExpcomp); - brightness->setValue (nextBrightness); - contrast->setValue (nextContrast); - black->setValue (nextBlack); - hlcompr->setValue (nextHlcompr); - hlcomprthresh->setValue (nextHlcomprthresh); - enaconn.block (true); - hrenabled->set_active (nextHLRecons); - enaconn.block (false); - if (nextHLRecons) - hlrbox->show(); - else if (!batchMode) - hlrbox->hide(); - if (!black->getAddMode()) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect - enableListener (); - - return false; -} - -void ToneCurve::setBatchMode (bool batchMode) { - ToolPanel::setBatchMode (batchMode); - method->append_text (M("GENERAL_UNCHANGED")); - - removeIfThere (abox, autolevels, false); - autolevels = Gtk::manage (new Gtk::CheckButton (M("TP_EXPOSURE_AUTOLEVELS"))); - autolevels->set_tooltip_markup (M("TP_EXPOSURE_AUTOLEVELS_TIP")); - autoconn = autolevels->signal_toggled().connect( sigc::mem_fun(*this, &ToneCurve::autolevels_toggled) ); - abox->pack_start (*autolevels); - - ToolPanel::setBatchMode (batchMode); - expcomp->showEditedCB (); - black->showEditedCB (); - hlcompr->showEditedCB (); - hlcomprthresh->showEditedCB (); - shcompr->showEditedCB (); - brightness->showEditedCB (); - contrast->showEditedCB (); - saturation->showEditedCB (); - - toneCurveMode->append_text (M("GENERAL_UNCHANGED")); - toneCurveMode2->append_text (M("GENERAL_UNCHANGED")); - - curveEditorG->setBatchMode (batchMode); - curveEditorG2->setBatchMode (batchMode); -} - -void ToneCurve::setAdjusterBehavior (bool expadd, bool hlcompadd, bool hlcompthreshadd, bool bradd, bool blackadd, bool shcompadd, bool contradd, bool satadd) { - - expcomp->setAddMode(expadd); - hlcompr->setAddMode(hlcompadd); - hlcomprthresh->setAddMode(hlcompthreshadd); - brightness->setAddMode(bradd); - black->setAddMode(blackadd); - shcompr->setAddMode(shcompadd); - contrast->setAddMode(contradd); - saturation->setAddMode(satadd); -} - -void ToneCurve::trimValues (rtengine::procparams::ProcParams* pp) { - - expcomp->trimValue(pp->toneCurve.expcomp); - hlcompr->trimValue(pp->toneCurve.hlcompr); - hlcomprthresh->trimValue(pp->toneCurve.hlcomprthresh); - brightness->trimValue(pp->toneCurve.brightness); - black->trimValue(pp->toneCurve.black); - shcompr->trimValue(pp->toneCurve.shcompr); - contrast->trimValue(pp->toneCurve.contrast); - saturation->trimValue(pp->toneCurve.saturation); -} - -void ToneCurve::updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve, /*LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma) { - - shape->updateBackgroundHistogram (histToneCurve); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "tonecurve.h" +#include "adjuster.h" +#include +#include +#include "ppversion.h" +#include "edit.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +ToneCurve::ToneCurve () : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LABEL")) { + + CurveListener::setMulti(true); + + std::vector bottomMilestones; + bottomMilestones.push_back( GradientMilestone(0., 0., 0., 0.) ); + bottomMilestones.push_back( GradientMilestone(1., 1., 1., 1.) ); + +//----------- Auto Levels ---------------------------------- + abox = Gtk::manage (new Gtk::HBox ()); + abox->set_border_width (2); + abox->set_spacing (10); + + autolevels = Gtk::manage (new Gtk::ToggleButton (M("TP_EXPOSURE_AUTOLEVELS"))); + autolevels->set_tooltip_markup (M("TP_EXPOSURE_AUTOLEVELS_TIP")); + autoconn = autolevels->signal_toggled().connect( sigc::mem_fun(*this, &ToneCurve::autolevels_toggled) ); + + lclip = Gtk::manage (new Gtk::Label (M("TP_EXPOSURE_CLIP"))); + lclip->set_tooltip_text (M("TP_EXPOSURE_CLIP_TIP")); + + sclip = Gtk::manage (new MySpinButton ()); + sclip->set_range (0.0, 0.99); + sclip->set_increments (0.01, 0.10); + sclip->set_value (0.02); + sclip->set_digits (2); + sclip->signal_value_changed().connect( sigc::mem_fun(*this, &ToneCurve::clip_changed) ); + + neutral = Gtk::manage (new Gtk::Button (M("TP_NEUTRAL"))); + neutral->set_tooltip_text (M("TP_NEUTRAL_TIP")); + neutralconn = neutral->signal_pressed().connect( sigc::mem_fun(*this, &ToneCurve::neutral_pressed) ); + neutral->show(); + + abox->pack_start (*autolevels, true, true, 0); + // pack_end is used for these controls as autolevels is replaceable using pack_start in batchmode + abox->pack_end (*neutral, true, true, 0); + abox->pack_end (*sclip, false, false, 0); + abox->pack_end (*lclip, false, false, 0); + pack_start (*abox); + +//-------------- Highlight Reconstruction ----------------- + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + hrenabled = Gtk::manage (new Gtk::CheckButton (M("TP_HLREC_LABEL"))); + hrenabled->set_active (false); + hrenabled->set_tooltip_markup (M("TP_HLREC_ENA_TOOLTIP")); + pack_start (*hrenabled); + + method = Gtk::manage (new MyComboBoxText ()); + method->append_text (M("TP_HLREC_LUMINANCE")); + method->append_text (M("TP_HLREC_CIELAB")); + method->append_text (M("TP_HLREC_COLOR")); + method->append_text (M("TP_HLREC_BLEND")); + + method->set_active (0); + hlrbox = Gtk::manage (new Gtk::HBox ()); + Gtk::Label* lab = Gtk::manage (new Gtk::Label (M("TP_HLREC_METHOD"))); + hlrbox->pack_start (*lab, Gtk::PACK_SHRINK, 4); + hlrbox->pack_start (*method); + pack_start (*hlrbox); + + enaconn = hrenabled->signal_toggled().connect( sigc::mem_fun(*this, &ToneCurve::hrenabledChanged) ); + methconn = method->signal_changed().connect ( sigc::mem_fun(*this, &ToneCurve::methodChanged) ); + + //----------- Exposure Compensation --------------------- + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + expcomp = Gtk::manage (new Adjuster (M("TP_EXPOSURE_EXPCOMP"), -5, 12, 0.05, 0)); + pack_start (*expcomp); + + //----------- Highlight recovery & threshold ------------- + hlcompr = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRHIGHLIGHTS"), 0, 500, 1, 0)); + pack_start (*hlcompr); + hlcomprthresh = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD"), 0, 100, 1, 33)); + pack_start (*hlcomprthresh); + +//----------- Black Level & Compression ------------------- + black = Gtk::manage (new Adjuster (M("TP_EXPOSURE_BLACKLEVEL"), -16384, 32768, 50, 0)); + pack_start (*black); + shcompr = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRSHADOWS"), 0, 100, 1, 50)); + pack_start (*shcompr); + + pack_start (*Gtk::manage (new Gtk::HSeparator())); + +//---------Brightness / Contrast ------------------------- + brightness = Gtk::manage (new Adjuster (M("TP_EXPOSURE_BRIGHTNESS"), -100, 100, 1, 0)); + pack_start (*brightness); + contrast = Gtk::manage (new Adjuster (M("TP_EXPOSURE_CONTRAST"), -100, 100, 1, 0)); + pack_start (*contrast); + saturation = Gtk::manage (new Adjuster (M("TP_EXPOSURE_SATURATION"), -100, 100, 1, 0)); + pack_start (*saturation); + +//----------- Curve 1 ------------------------------ + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + toneCurveMode = Gtk::manage (new MyComboBoxText ()); + toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_STANDARD")); + toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_WEIGHTEDSTD")); + toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE")); + toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING")); + toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_LUMINANCE")); + toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_PERCEPTUAL")); + toneCurveMode->set_active (0); + toneCurveMode->set_tooltip_text(M("TP_EXPOSURE_TCMODE_LABEL1")); + + curveEditorG = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_EXPOSURE_CURVEEDITOR1")); + curveEditorG->setCurveListener (this); + + shape = static_cast(curveEditorG->addCurve(CT_Diagonal, "", toneCurveMode)); + shape->setEditID(EUID_ToneCurve1, BT_IMAGEFLOAT); + shape->setBottomBarBgGradient(bottomMilestones); + shape->setLeftBarBgGradient(bottomMilestones); + + // This will add the reset button at the end of the curveType buttons + curveEditorG->curveListComplete(); + + pack_start( *curveEditorG, Gtk::PACK_SHRINK, 2); + + tcmodeconn = toneCurveMode->signal_changed().connect( sigc::mem_fun(*this, &ToneCurve::curveMode1Changed), true ); + +//----------- Curve 2 ------------------------------ + + toneCurveMode2 = Gtk::manage (new MyComboBoxText ()); + toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_STANDARD")); + toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_WEIGHTEDSTD")); + toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE")); + toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING")); + toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_LUMINANCE")); + toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_PERCEPTUAL")); + toneCurveMode2->set_active (0); + toneCurveMode2->set_tooltip_text(M("TP_EXPOSURE_TCMODE_LABEL2")); + + curveEditorG2 = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_EXPOSURE_CURVEEDITOR2")); + curveEditorG2->setCurveListener (this); + + shape2 = static_cast(curveEditorG2->addCurve(CT_Diagonal, "", toneCurveMode2)); + shape2->setEditID(EUID_ToneCurve2, BT_IMAGEFLOAT); + shape2->setBottomBarBgGradient(bottomMilestones); + shape2->setLeftBarBgGradient(bottomMilestones); + + // This will add the reset button at the end of the curveType buttons + curveEditorG2->curveListComplete(); + curveEditorG2->setTooltip(M("TP_EXPOSURE_CURVEEDITOR2_TOOLTIP")); + + pack_start( *curveEditorG2, Gtk::PACK_SHRINK, 2); + + tcmode2conn = toneCurveMode2->signal_changed().connect( sigc::mem_fun(*this, &ToneCurve::curveMode2Changed), true ); + +// --------- Set Up Listeners ------------- + expcomp->setAdjusterListener (this); + brightness->setAdjusterListener (this); + black->setAdjusterListener (this); + hlcompr->setAdjusterListener (this); + hlcomprthresh->setAdjusterListener (this); + shcompr->setAdjusterListener (this); + contrast->setAdjusterListener (this); + saturation->setAdjusterListener (this); +} + +ToneCurve::~ToneCurve () { + delete curveEditorG; + delete curveEditorG2; +} + +void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + tcmodeconn.block(true); + tcmode2conn.block(true); + autoconn.block (true); + + autolevels->set_active (pp->toneCurve.autoexp); + lastAuto = pp->toneCurve.autoexp; + sclip->set_value (pp->toneCurve.clip); + + expcomp->setValue (pp->toneCurve.expcomp); + black->setValue (pp->toneCurve.black); + hlcompr->setValue (pp->toneCurve.hlcompr); + hlcomprthresh->setValue (pp->toneCurve.hlcomprthresh); + shcompr->setValue (pp->toneCurve.shcompr); + if (!black->getAddMode()) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect + brightness->setValue (pp->toneCurve.brightness); + contrast->setValue (pp->toneCurve.contrast); + saturation->setValue (pp->toneCurve.saturation); + shape->setCurve (pp->toneCurve.curve); + shape2->setCurve (pp->toneCurve.curve2); + + toneCurveMode->set_active(pp->toneCurve.curveMode); + toneCurveMode2->set_active(pp->toneCurve.curveMode2); + + if (pedited) { + expcomp->setEditedState (pedited->toneCurve.expcomp ? Edited : UnEdited); + black->setEditedState (pedited->toneCurve.black ? Edited : UnEdited); + hlcompr->setEditedState (pedited->toneCurve.hlcompr ? Edited : UnEdited); + hlcomprthresh->setEditedState (pedited->toneCurve.hlcomprthresh ? Edited : UnEdited); + shcompr->setEditedState (pedited->toneCurve.shcompr ? Edited : UnEdited); + brightness->setEditedState (pedited->toneCurve.brightness ? Edited : UnEdited); + contrast->setEditedState (pedited->toneCurve.contrast ? Edited : UnEdited); + saturation->setEditedState (pedited->toneCurve.saturation ? Edited : UnEdited); + autolevels->set_inconsistent (!pedited->toneCurve.autoexp); + clipDirty = pedited->toneCurve.clip; + shape->setUnChanged (!pedited->toneCurve.curve); + shape2->setUnChanged (!pedited->toneCurve.curve2); + if (!pedited->toneCurve.curveMode) { + toneCurveMode->set_active(6); + } + if (!pedited->toneCurve.curveMode2) { + toneCurveMode2->set_active(6); + } + } + if (pedited) + hrenabled->set_inconsistent (!pedited->toneCurve.hrenabled); + enaconn.block (true); + hrenabled->set_active (pp->toneCurve.hrenabled); + enaconn.block (false); + + if (pedited && !pedited->toneCurve.method) + method->set_active (4); + else if (pp->toneCurve.method=="Luminance") + method->set_active (0); + else if (pp->toneCurve.method=="CIELab blending") + method->set_active (1); + else if (pp->toneCurve.method=="Color") + method->set_active (2); + else if (pp->toneCurve.method=="Blend") + method->set_active (3); + + if (!batchMode) { + if (hrenabled->get_active()) + hlrbox->show(); + else + hlrbox->hide(); + } + lasthrEnabled = pp->toneCurve.hrenabled; + + autoconn.block (false); + tcmode2conn.block(false); + tcmodeconn.block(false); + + enableListener (); +} + +void ToneCurve::autoOpenCurve () { + shape->openIfNonlinear(); + shape2->openIfNonlinear(); +} + +void ToneCurve::setEditProvider (EditDataProvider *provider) { + shape->setEditProvider(provider); + shape2->setEditProvider(provider); +} + +void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->toneCurve.autoexp = autolevels->get_active(); + pp->toneCurve.clip = sclip->get_value (); + pp->toneCurve.expcomp = expcomp->getValue (); + pp->toneCurve.black = (int)black->getValue (); + pp->toneCurve.hlcompr = (int)hlcompr->getValue (); + pp->toneCurve.hlcomprthresh = (int)hlcomprthresh->getValue (); + pp->toneCurve.shcompr = (int)shcompr->getValue (); + pp->toneCurve.brightness = (int)brightness->getValue (); + pp->toneCurve.contrast = (int)contrast->getValue (); + pp->toneCurve.saturation = (int)saturation->getValue (); + pp->toneCurve.curve = shape->getCurve (); + pp->toneCurve.curve2 = shape2->getCurve (); + + int tcMode = toneCurveMode->get_active_row_number(); + if (tcMode == 0) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_STD; + else if (tcMode == 1) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_WEIGHTEDSTD; + else if (tcMode == 2) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_FILMLIKE; + else if (tcMode == 3) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_SATANDVALBLENDING; + else if (tcMode == 4) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_LUMINANCE; + else if (tcMode == 5) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_PERCEPTUAL; + + tcMode = toneCurveMode2->get_active_row_number(); + if (tcMode == 0) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD; + else if (tcMode == 1) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_WEIGHTEDSTD; + else if (tcMode == 2) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_FILMLIKE; + else if (tcMode == 3) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_SATANDVALBLENDING; + else if (tcMode == 4) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_LUMINANCE; + else if (tcMode == 5) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_PERCEPTUAL; + + if (pedited) { + pedited->toneCurve.expcomp = expcomp->getEditedState (); + pedited->toneCurve.black = black->getEditedState (); + pedited->toneCurve.hlcompr = hlcompr->getEditedState (); + pedited->toneCurve.hlcomprthresh = hlcomprthresh->getEditedState (); + pedited->toneCurve.shcompr = shcompr->getEditedState (); + pedited->toneCurve.brightness = brightness->getEditedState (); + pedited->toneCurve.contrast = contrast->getEditedState (); + pedited->toneCurve.saturation = saturation->getEditedState (); + pedited->toneCurve.autoexp = !autolevels->get_inconsistent(); + pedited->toneCurve.clip = clipDirty; + pedited->toneCurve.curve = !shape->isUnChanged (); + pedited->toneCurve.curve2 = !shape2->isUnChanged (); + pedited->toneCurve.curveMode = toneCurveMode->get_active_row_number() != 6; + pedited->toneCurve.curveMode2 = toneCurveMode2->get_active_row_number() != 6; + } + if (pedited) { + pedited->toneCurve.method = method->get_active_row_number()!=4; + pedited->toneCurve.hrenabled = !hrenabled->get_inconsistent(); + } + + pp->toneCurve.hrenabled = hrenabled->get_active(); + if (method->get_active_row_number()==0) + pp->toneCurve.method = "Luminance"; + else if (method->get_active_row_number()==1) + pp->toneCurve.method = "CIELab blending"; + else if (method->get_active_row_number()==2) + pp->toneCurve.method = "Color"; + else if (method->get_active_row_number()==3) + pp->toneCurve.method = "Blend"; +} + +void ToneCurve::hrenabledChanged () { + + if (multiImage) { + if (hrenabled->get_inconsistent()) { + hrenabled->set_inconsistent (false); + enaconn.block (true); + hrenabled->set_active (false); + enaconn.block (false); + } + else if (lasthrEnabled) + hrenabled->set_inconsistent (true); + + lasthrEnabled = hrenabled->get_active (); + } + + if (!batchMode) { + if (hrenabled->get_active()) + hlrbox->show(); + else + hlrbox->hide(); + } + + if (listener) { + // Switch off auto exposure if user changes enabled manually + if (autolevels->get_active() ) { + autoconn.block(true); + autolevels->set_active (false); + autoconn.block(false); + autolevels->set_inconsistent (false); + } + if (hrenabled->get_active ()) + listener->panelChanged (EvHREnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvHREnabled, M("GENERAL_DISABLED")); + } +} +void ToneCurve::methodChanged () { + + if (listener) { + if (hrenabled->get_active ()) + listener->panelChanged (EvHRMethod, method->get_active_text ()); + } +} +void ToneCurve::setRaw (bool raw) { + + disableListener (); + method->set_sensitive (raw); + hrenabled->set_sensitive (raw); + enableListener (); +} + + +void ToneCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + expcomp->setDefault (defParams->toneCurve.expcomp); + brightness->setDefault (defParams->toneCurve.brightness); + black->setDefault (defParams->toneCurve.black); + hlcompr->setDefault (defParams->toneCurve.hlcompr); + hlcomprthresh->setDefault (defParams->toneCurve.hlcomprthresh); + shcompr->setDefault (defParams->toneCurve.shcompr); + contrast->setDefault (defParams->toneCurve.contrast); + saturation->setDefault (defParams->toneCurve.saturation); + + if (pedited) { + expcomp->setDefaultEditedState (pedited->toneCurve.expcomp ? Edited : UnEdited); + black->setDefaultEditedState (pedited->toneCurve.black ? Edited : UnEdited); + hlcompr->setDefaultEditedState (pedited->toneCurve.hlcompr ? Edited : UnEdited); + hlcomprthresh->setDefaultEditedState (pedited->toneCurve.hlcomprthresh ? Edited : UnEdited); + shcompr->setDefaultEditedState (pedited->toneCurve.shcompr ? Edited : UnEdited); + brightness->setDefaultEditedState (pedited->toneCurve.brightness ? Edited : UnEdited); + contrast->setDefaultEditedState (pedited->toneCurve.contrast ? Edited : UnEdited); + saturation->setDefaultEditedState (pedited->toneCurve.saturation ? Edited : UnEdited); + } + else { + expcomp->setDefaultEditedState (Irrelevant); + black->setDefaultEditedState (Irrelevant); + hlcompr->setDefaultEditedState (Irrelevant); + hlcomprthresh->setDefaultEditedState (Irrelevant); + shcompr->setDefaultEditedState (Irrelevant); + brightness->setDefaultEditedState (Irrelevant); + contrast->setDefaultEditedState (Irrelevant); + saturation->setDefaultEditedState (Irrelevant); + } +} + +void ToneCurve::curveChanged (CurveEditor* ce) { + + if (listener) { + if (ce == shape) + listener->panelChanged (EvToneCurve1, M("HISTORY_CUSTOMCURVE")); + else if (ce == shape2) + listener->panelChanged (EvToneCurve2, M("HISTORY_CUSTOMCURVE")); + } +} + +void ToneCurve::curveMode1Changed () { + //if (listener) listener->panelChanged (EvToneCurveMode, toneCurveMode->get_active_text()); + if (listener) Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::curveMode1Changed_)); +} + +bool ToneCurve::curveMode1Changed_ () { + if (listener) listener->panelChanged (EvToneCurveMode1, toneCurveMode->get_active_text()); + return false; +} + +void ToneCurve::curveMode2Changed () { + //if (listener) listener->panelChanged (EvToneCurveMode, toneCurveMode->get_active_text()); + if (listener) Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::curveMode2Changed_)); +} + +bool ToneCurve::curveMode2Changed_ () { + if (listener) listener->panelChanged (EvToneCurveMode2, toneCurveMode2->get_active_text()); + return false; +} + +float ToneCurve::blendPipetteValues(CurveEditor *ce, float chan1, float chan2, float chan3) { + // assuming that all the channels are used... + if (ce == shape) { + if (toneCurveMode->get_active_row_number() == 4) + return chan1*0.2126729f + chan2*0.7151521f + chan3*0.0721750f; + } + else if (ce == shape2) { + if (toneCurveMode2->get_active_row_number() == 4) + return chan1*0.2126729f + chan2*0.7151521f + chan3*0.0721750f; + } + return CurveListener::blendPipetteValues(ce, chan1, chan2, chan3); +} + +void ToneCurve::adjusterChanged (Adjuster* a, double newval) { + + // Switch off auto exposure if user changes sliders manually + if (autolevels->get_active() && (a==expcomp || a==brightness || a==contrast || a==black || a==hlcompr || a==hlcomprthresh)) { + autoconn.block(true); + autolevels->set_active (false); + autoconn.block(false); + autolevels->set_inconsistent (false); + } + + if (!listener) + return; + + Glib::ustring costr; + if (a==expcomp) + costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), a->getValue()); + else + costr = Glib::ustring::format ((int)a->getValue()); + + if (a==expcomp) + listener->panelChanged (EvExpComp, costr); + else if (a==brightness) + listener->panelChanged (EvBrightness, costr); + else if (a==black){ + listener->panelChanged (EvBlack, costr); + if (!black->getAddMode()) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect + } + else if (a==contrast) + listener->panelChanged (EvContrast, costr); + else if (a==saturation) + listener->panelChanged (EvSaturation, costr); + else if (a==hlcompr) + listener->panelChanged (EvHLCompr, costr); + else if (a==hlcomprthresh) + listener->panelChanged (EvHLComprThreshold, costr); + else if (a==shcompr) + listener->panelChanged (EvSHCompr, costr); +} + +void ToneCurve::neutral_pressed () { +// This method deselects auto levels and HL reconstruction auto +// and sets neutral values to params in exposure panel + + if (batchMode) { + autolevels->set_inconsistent (false); + autoconn.block (true); + autolevels->set_active (false); + autoconn.block (false); + + lastAuto = autolevels->get_active (); + } + else { //!batchMode + autolevels->set_active (false); + autolevels->set_inconsistent (false); + } + + expcomp->setValue(0); + hlcompr->setValue(0); + hlcomprthresh->setValue(0); + brightness->setValue(0); + black->setValue(0); + shcompr->setValue(50); + enaconn.block (true); + hrenabled->set_active (false); + enaconn.block (false); + if (!batchMode) + hlrbox->hide(); + if (!black->getAddMode()) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect + contrast->setValue(0); + //saturation->setValue(0); + + listener->panelChanged (EvNeutralExp, M("GENERAL_ENABLED")); +} +void ToneCurve::autolevels_toggled () { + + if (batchMode) { + if (autolevels->get_inconsistent()) { + autolevels->set_inconsistent (false); + autoconn.block (true); + autolevels->set_active (false); + autoconn.block (false); + } + else if (lastAuto) + autolevels->set_inconsistent (true); + + lastAuto = autolevels->get_active (); + + expcomp->setEditedState (UnEdited); + brightness->setEditedState (UnEdited); + contrast->setEditedState (UnEdited); + black->setEditedState (UnEdited); + hlcompr->setEditedState (UnEdited); + hlcomprthresh->setEditedState (UnEdited); + if (expcomp->getAddMode()) + expcomp->setValue (0); + if (brightness->getAddMode()) + brightness->setValue (0); + if (contrast->getAddMode()) + contrast->setValue (0); + if (black->getAddMode()) + black->setValue (0); + if (hlcompr->getAddMode()) + hlcompr->setValue (0); + if (hlcomprthresh->getAddMode()) + hlcomprthresh->setValue (0); + + if (listener) { + if (!autolevels->get_inconsistent()) { + if (autolevels->get_active ()) + listener->panelChanged (EvAutoExp, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvFixedExp, M("GENERAL_DISABLED")); + } + } + } + else if (/* !batchMode && */ listener) { + if (autolevels->get_active()) { + listener->panelChanged (EvAutoExp, M("GENERAL_ENABLED")); + waitForAutoExp (); + if (!black->getAddMode()) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect + } + else { + listener->panelChanged (EvFixedExp, M("GENERAL_DISABLED")); + } + } +} + +void ToneCurve::clip_changed () { + + clipDirty = true; + if (autolevels->get_active() && listener) + Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::clip_changed_)); +} + +bool ToneCurve::clip_changed_ () { + + if (listener) { + listener->panelChanged (EvClip, Glib::ustring::format (std::setprecision(5), sclip->get_value())); + if (!batchMode) + waitForAutoExp (); + } + return false; +} + +void ToneCurve::waitForAutoExp () { + + sclip->set_sensitive (false); + expcomp->setEnabled (false); + brightness->setEnabled (false); + contrast->setEnabled (false); + black->setEnabled (false); + hlcompr->setEnabled (false); + hlcomprthresh->setEnabled (false); + shcompr->setEnabled (false); + contrast->setEnabled (false); + saturation->setEnabled (false); + curveEditorG->set_sensitive (false); + toneCurveMode->set_sensitive (false); + curveEditorG2->set_sensitive (false); + toneCurveMode2->set_sensitive (false); + hrenabled->set_sensitive(false); + method->set_sensitive(false); +} + +int autoExpChangedUI (void* data) { + (static_cast(data))->autoExpComputed_ (); + return 0; +} + +void ToneCurve::autoExpChanged (double expcomp, int bright, int contr, int black, int hlcompr, int hlcomprthresh, bool hlrecons) { + + nextBlack = black; + nextExpcomp = expcomp; + nextBrightness = bright; + nextContrast = contr; + nextHlcompr = hlcompr; + nextHlcomprthresh = hlcomprthresh; + nextHLRecons = hlrecons; + g_idle_add (autoExpChangedUI, this); +} + +void ToneCurve::enableAll () { + + sclip->set_sensitive (true); + expcomp->setEnabled (true); + brightness->setEnabled (true); + black->setEnabled (true); + hlcompr->setEnabled (true); + hlcomprthresh->setEnabled (true); + shcompr->setEnabled (true); + contrast->setEnabled (true); + saturation->setEnabled (true); + curveEditorG->set_sensitive (true); + toneCurveMode->set_sensitive (true); + curveEditorG2->set_sensitive (true); + toneCurveMode2->set_sensitive (true); + hrenabled->set_sensitive(true); + method->set_sensitive(true); +} + +bool ToneCurve::autoExpComputed_ () { + + GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected + disableListener (); + enableAll (); + expcomp->setValue (nextExpcomp); + brightness->setValue (nextBrightness); + contrast->setValue (nextContrast); + black->setValue (nextBlack); + hlcompr->setValue (nextHlcompr); + hlcomprthresh->setValue (nextHlcomprthresh); + enaconn.block (true); + hrenabled->set_active (nextHLRecons); + enaconn.block (false); + if (nextHLRecons) + hlrbox->show(); + else if (!batchMode) + hlrbox->hide(); + if (!black->getAddMode()) shcompr->set_sensitive(!((int)black->getValue ()==0)); //at black=0 shcompr value has no effect + enableListener (); + + return false; +} + +void ToneCurve::setBatchMode (bool batchMode) { + ToolPanel::setBatchMode (batchMode); + method->append_text (M("GENERAL_UNCHANGED")); + + removeIfThere (abox, autolevels, false); + autolevels = Gtk::manage (new Gtk::CheckButton (M("TP_EXPOSURE_AUTOLEVELS"))); + autolevels->set_tooltip_markup (M("TP_EXPOSURE_AUTOLEVELS_TIP")); + autoconn = autolevels->signal_toggled().connect( sigc::mem_fun(*this, &ToneCurve::autolevels_toggled) ); + abox->pack_start (*autolevels); + + ToolPanel::setBatchMode (batchMode); + expcomp->showEditedCB (); + black->showEditedCB (); + hlcompr->showEditedCB (); + hlcomprthresh->showEditedCB (); + shcompr->showEditedCB (); + brightness->showEditedCB (); + contrast->showEditedCB (); + saturation->showEditedCB (); + + toneCurveMode->append_text (M("GENERAL_UNCHANGED")); + toneCurveMode2->append_text (M("GENERAL_UNCHANGED")); + + curveEditorG->setBatchMode (batchMode); + curveEditorG2->setBatchMode (batchMode); +} + +void ToneCurve::setAdjusterBehavior (bool expadd, bool hlcompadd, bool hlcompthreshadd, bool bradd, bool blackadd, bool shcompadd, bool contradd, bool satadd) { + + expcomp->setAddMode(expadd); + hlcompr->setAddMode(hlcompadd); + hlcomprthresh->setAddMode(hlcompthreshadd); + brightness->setAddMode(bradd); + black->setAddMode(blackadd); + shcompr->setAddMode(shcompadd); + contrast->setAddMode(contradd); + saturation->setAddMode(satadd); +} + +void ToneCurve::trimValues (rtengine::procparams::ProcParams* pp) { + + expcomp->trimValue(pp->toneCurve.expcomp); + hlcompr->trimValue(pp->toneCurve.hlcompr); + hlcomprthresh->trimValue(pp->toneCurve.hlcomprthresh); + brightness->trimValue(pp->toneCurve.brightness); + black->trimValue(pp->toneCurve.black); + shcompr->trimValue(pp->toneCurve.shcompr); + contrast->trimValue(pp->toneCurve.contrast); + saturation->trimValue(pp->toneCurve.saturation); +} + +void ToneCurve::updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve, /*LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma) { + + shape->updateBackgroundHistogram (histToneCurve); +} diff --git a/rtgui/toolpanel.cc b/rtgui/toolpanel.cc index db8e10d00..9bf9bdd77 100644 --- a/rtgui/toolpanel.cc +++ b/rtgui/toolpanel.cc @@ -1,151 +1,151 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "toolpanel.h" -#include "toolpanelcoord.h" -#include "guiutils.h" - -using namespace rtengine::procparams; - - -ToolVBox::ToolVBox() { - updateStyle(); -} - -void ToolVBox::updateStyle() { - if (options.slimUI) { - set_spacing(1); // Vertical space between tools - set_border_width(1); // Space separating the tab's frame and the tools - } - else { - set_spacing(2); // Vertical space between tools - set_border_width(1); // Space separating the tab's frame and the tools 3 - } -} - -void ToolVBox::on_style_changed (const Glib::RefPtr& style) { - updateStyle(); -} - -ToolParamBlock::ToolParamBlock() { - updateStyle(); -} - -void ToolParamBlock::updateStyle() { - if (options.slimUI) { - set_spacing(2); // Vertical space between parameters in a single tool - set_border_width(6); // Space separating the parameters of a tool and its surrounding frame 6 - } - else { - set_spacing(4); // Vertical space between parameters in a single tool - set_border_width(8); // Space separating the parameters of a tool and its surrounding frame 8 - } -} - -void ToolParamBlock::on_style_changed (const Glib::RefPtr& style) { - updateStyle(); -} - -FoldableToolPanel::FoldableToolPanel(Gtk::Box* content, Glib::ustring toolName, Glib::ustring UILabel, bool need11, bool useEnabled) : ToolPanel(toolName, need11), parentContainer(NULL), exp(NULL), lastEnabled(true) -{ - if (!content) - return; - -// exp->set_border_width (5); -// exp->set_use_markup (true); - if (need11) { - Gtk::HBox *titleHBox = Gtk::manage(new Gtk::HBox()); - - Gtk::Label *label = Gtk::manage(new Gtk::Label()); - label->set_markup(Glib::ustring("") + escapeHtmlChars(UILabel) + Glib::ustring("")); - label->set_alignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER); - titleHBox->pack_start(*label, Gtk::PACK_EXPAND_WIDGET, 0); - - RTImage *image = Gtk::manage (new RTImage("zoom-100-identifier.png")); - image->set_tooltip_text(M("TP_GENERAL_11SCALE_TOOLTIP")); - titleHBox->pack_end(*image, Gtk::PACK_SHRINK, 0); - - exp = Gtk::manage (new MyExpander (useEnabled, titleHBox)); - } - else { - exp = Gtk::manage (new MyExpander (useEnabled, UILabel)); - } - exp->signal_button_release_event().connect_notify( sigc::mem_fun(this, &FoldableToolPanel::foldThemAll) ); - enaConn = signal_enabled_toggled().connect( sigc::mem_fun(*this, &FoldableToolPanel::enabled_toggled) ); - - exp->add (*content); - exp->show (); -} - -void FoldableToolPanel::foldThemAll (GdkEventButton* event) { - if (event->button == 3) { - if (listener) - (static_cast(listener))->foldAllButOne( parentContainer, this); - else - (static_cast(tmp))->foldAllButOne( parentContainer, this); - } -} - -void FoldableToolPanel::enabled_toggled() { - if (multiImage) { - if (exp->get_inconsistent()) { - exp->set_inconsistent (false); - enaConn.block (true); - exp->setEnabled (false); - enaConn.block (false); - } - else if (lastEnabled) - exp->set_inconsistent (true); - - lastEnabled = exp->getEnabled(); - } - enabledChanged(); -} - -bool FoldableToolPanel::get_inconsistent() { - return exp->get_inconsistent(); -} - -void FoldableToolPanel::set_inconsistent(bool isInconsistent) { - exp->set_inconsistent(isInconsistent); -} - -bool FoldableToolPanel::getEnabled() { - return exp->getEnabled(); -} - -// do not emit the enabled_toggled event -void FoldableToolPanel::setEnabled(bool isEnabled) { - enaConn.block (true); - exp->setEnabled(isEnabled); - lastEnabled = isEnabled; - enaConn.block (false); -} - -void FoldableToolPanel::setEnabledTooltipMarkup(Glib::ustring tooltipMarkup) { - if (exp) - exp->set_tooltip_markup(tooltipMarkup); -} - -void FoldableToolPanel::setEnabledTooltipText(Glib::ustring tooltipText) { - if (exp) - exp->set_tooltip_text(tooltipText); -} - - - +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "toolpanel.h" +#include "toolpanelcoord.h" +#include "guiutils.h" + +using namespace rtengine::procparams; + + +ToolVBox::ToolVBox() { + updateStyle(); +} + +void ToolVBox::updateStyle() { + if (options.slimUI) { + set_spacing(1); // Vertical space between tools + set_border_width(1); // Space separating the tab's frame and the tools + } + else { + set_spacing(2); // Vertical space between tools + set_border_width(1); // Space separating the tab's frame and the tools 3 + } +} + +void ToolVBox::on_style_changed (const Glib::RefPtr& style) { + updateStyle(); +} + +ToolParamBlock::ToolParamBlock() { + updateStyle(); +} + +void ToolParamBlock::updateStyle() { + if (options.slimUI) { + set_spacing(2); // Vertical space between parameters in a single tool + set_border_width(6); // Space separating the parameters of a tool and its surrounding frame 6 + } + else { + set_spacing(4); // Vertical space between parameters in a single tool + set_border_width(8); // Space separating the parameters of a tool and its surrounding frame 8 + } +} + +void ToolParamBlock::on_style_changed (const Glib::RefPtr& style) { + updateStyle(); +} + +FoldableToolPanel::FoldableToolPanel(Gtk::Box* content, Glib::ustring toolName, Glib::ustring UILabel, bool need11, bool useEnabled) : ToolPanel(toolName, need11), parentContainer(NULL), exp(NULL), lastEnabled(true) +{ + if (!content) + return; + +// exp->set_border_width (5); +// exp->set_use_markup (true); + if (need11) { + Gtk::HBox *titleHBox = Gtk::manage(new Gtk::HBox()); + + Gtk::Label *label = Gtk::manage(new Gtk::Label()); + label->set_markup(Glib::ustring("") + escapeHtmlChars(UILabel) + Glib::ustring("")); + label->set_alignment(Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER); + titleHBox->pack_start(*label, Gtk::PACK_EXPAND_WIDGET, 0); + + RTImage *image = Gtk::manage (new RTImage("zoom-100-identifier.png")); + image->set_tooltip_text(M("TP_GENERAL_11SCALE_TOOLTIP")); + titleHBox->pack_end(*image, Gtk::PACK_SHRINK, 0); + + exp = Gtk::manage (new MyExpander (useEnabled, titleHBox)); + } + else { + exp = Gtk::manage (new MyExpander (useEnabled, UILabel)); + } + exp->signal_button_release_event().connect_notify( sigc::mem_fun(this, &FoldableToolPanel::foldThemAll) ); + enaConn = signal_enabled_toggled().connect( sigc::mem_fun(*this, &FoldableToolPanel::enabled_toggled) ); + + exp->add (*content); + exp->show (); +} + +void FoldableToolPanel::foldThemAll (GdkEventButton* event) { + if (event->button == 3) { + if (listener) + (static_cast(listener))->foldAllButOne( parentContainer, this); + else + (static_cast(tmp))->foldAllButOne( parentContainer, this); + } +} + +void FoldableToolPanel::enabled_toggled() { + if (multiImage) { + if (exp->get_inconsistent()) { + exp->set_inconsistent (false); + enaConn.block (true); + exp->setEnabled (false); + enaConn.block (false); + } + else if (lastEnabled) + exp->set_inconsistent (true); + + lastEnabled = exp->getEnabled(); + } + enabledChanged(); +} + +bool FoldableToolPanel::get_inconsistent() { + return exp->get_inconsistent(); +} + +void FoldableToolPanel::set_inconsistent(bool isInconsistent) { + exp->set_inconsistent(isInconsistent); +} + +bool FoldableToolPanel::getEnabled() { + return exp->getEnabled(); +} + +// do not emit the enabled_toggled event +void FoldableToolPanel::setEnabled(bool isEnabled) { + enaConn.block (true); + exp->setEnabled(isEnabled); + lastEnabled = isEnabled; + enaConn.block (false); +} + +void FoldableToolPanel::setEnabledTooltipMarkup(Glib::ustring tooltipMarkup) { + if (exp) + exp->set_tooltip_markup(tooltipMarkup); +} + +void FoldableToolPanel::setEnabledTooltipText(Glib::ustring tooltipText) { + if (exp) + exp->set_tooltip_text(tooltipText); +} + + + diff --git a/rtgui/vibrance.cc b/rtgui/vibrance.cc index 54fcdbd39..4d67d5aeb 100644 --- a/rtgui/vibrance.cc +++ b/rtgui/vibrance.cc @@ -1,365 +1,365 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ - -#include "vibrance.h" -#include "../rtengine/color.h" - -using namespace rtengine; -using namespace rtengine::procparams; - -Vibrance::Vibrance () : FoldableToolPanel(this, "vibrance", M("TP_VIBRANCE_LABEL"), false, true) { - - std::vector milestones; - float R, G, B; - // -0.1 rad < Hue < 1.6 rad - Color::hsv2rgb01(0.92f, 0.45f, 0.6f, R, G, B); - milestones.push_back( GradientMilestone(0.0, double(R), double(G), double(B)) ); - Color::hsv2rgb01(0.14056f, 0.45f, 0.6f, R, G, B); - milestones.push_back( GradientMilestone(1.0, double(R), double(G), double(B)) ); - - saturated = Gtk::manage(new Adjuster (M("TP_VIBRANCE_SATURATED"),-100.,100.,1.,0.)); - saturated->setAdjusterListener (this); - saturated->set_sensitive(false); - //if (saturated->delay < 1000) saturated->delay = 1000; - pack_start( *saturated, Gtk::PACK_SHRINK, 0); - - pastels = Gtk::manage(new Adjuster (M("TP_VIBRANCE_PASTELS"),-100.,100.,1.,0.)); - pastels->setAdjusterListener (this); - //if (pastels->delay < 1000) pastels->delay = 1000; - pack_start( *pastels, Gtk::PACK_SHRINK, 0); - - psThreshold = Gtk::manage (new ThresholdAdjuster (M("TP_VIBRANCE_PSTHRESHOLD"), -100., 100., 0., M("TP_VIBRANCE_PSTHRESHOLD_WEIGTHING"), 0, 0., 100., 75., M("TP_VIBRANCE_PSTHRESHOLD_SATTHRESH"), 0, this, false)); - psThreshold->setAdjusterListener (this); - psThreshold->set_tooltip_markup(M("TP_VIBRANCE_PSTHRESHOLD_TOOLTIP")); - psThreshold->set_sensitive(false); - //if (psThreshold->delay < 1000) psThreshold->delay = 1000; - pack_start( *psThreshold, Gtk::PACK_SHRINK, 0); - - protectSkins = Gtk::manage (new Gtk::CheckButton (M("TP_VIBRANCE_PROTECTSKINS"))); - protectSkins->set_active (true); - pack_start(*protectSkins, Gtk::PACK_SHRINK, 0); - - avoidColorShift = Gtk::manage (new Gtk::CheckButton (M("TP_VIBRANCE_AVOIDCOLORSHIFT"))); - avoidColorShift->set_active (true); - pack_start(*avoidColorShift, Gtk::PACK_SHRINK, 0); - - pastSatTog = Gtk::manage (new Gtk::CheckButton (M("TP_VIBRANCE_PASTSATTOG"))); - pastSatTog->set_active (true); - pack_start(*pastSatTog, Gtk::PACK_SHRINK, 0); - - curveEditorGG = new CurveEditorGroup (options.lastVibranceCurvesDir, M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_LABEL")); - curveEditorGG->setCurveListener (this); - - skinTonesCurve = static_cast(curveEditorGG->addCurve(CT_Diagonal, M("TP_VIBRANCE_CURVEEDITOR_SKINTONES"))); - skinTonesCurve->setTooltip(M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_TOOLTIP")); - skinTonesCurve->setBottomBarBgGradient(milestones); - skinTonesCurve->setLeftBarBgGradient(milestones); - skinTonesCurve->setRangeLabels( - M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE1"), M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE2"), - M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE3"), M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE4") - ); - skinTonesCurve->setRangeDefaultMilestones(0.1, 0.4, 0.85); - curveEditorGG->curveListComplete(); - - pack_start (*curveEditorGG, Gtk::PACK_SHRINK, 4); - - show (); - - pskinsconn = protectSkins->signal_toggled().connect( sigc::mem_fun(*this, &Vibrance::protectskins_toggled) ); - ashiftconn = avoidColorShift->signal_toggled().connect( sigc::mem_fun(*this, &Vibrance::avoidcolorshift_toggled) ); - pastsattogconn = pastSatTog->signal_toggled().connect( sigc::mem_fun(*this, &Vibrance::pastsattog_toggled) ); -} - -Vibrance::~Vibrance () { - delete curveEditorGG; -} - -void Vibrance::read(const ProcParams* pp, const ParamsEdited* pedited) { - disableListener (); - - if(pedited ){ - set_inconsistent (multiImage && !pedited->vibrance.enabled); - pastels->setEditedState (pedited->vibrance.pastels ? Edited : UnEdited); - saturated->setEditedState (pedited->vibrance.saturated ? Edited : UnEdited); - psThreshold->setEditedState (pedited->vibrance.psthreshold ? Edited : UnEdited); - protectSkins->set_inconsistent (!pedited->vibrance.protectskins); - avoidColorShift->set_inconsistent (!pedited->vibrance.avoidcolorshift); - pastSatTog->set_inconsistent (!pedited->vibrance.pastsattog); - skinTonesCurve->setUnChanged (!pedited->vibrance.skintonescurve); - } - - setEnabled (pp->vibrance.enabled); - - pskinsconn.block (true); - protectSkins->set_active (pp->vibrance.protectskins); - pskinsconn.block (false); - lastProtectSkins = pp->vibrance.protectskins; - - ashiftconn.block (true); - avoidColorShift->set_active (pp->vibrance.avoidcolorshift); - ashiftconn.block (false); - lastAvoidColorShift = pp->vibrance.avoidcolorshift; - - pastsattogconn.block (true); - pastSatTog->set_active (pp->vibrance.pastsattog); - pastsattogconn.block (false); - lastPastSatTog = pp->vibrance.pastsattog; - - pastels->setValue (pp->vibrance.pastels); - psThreshold->setValue (pp->vibrance.psthreshold); - - if (lastPastSatTog) { - // Link both slider, so we set saturated and psThresholds unsensitive - psThreshold->set_sensitive(false); - saturated->set_sensitive(false); - saturated->setValue (pp->vibrance.pastels); // Pastels and Saturated are linked - } - else { - // Separate sliders, so we set saturated and psThresholds sensitive again - psThreshold->set_sensitive(true); - saturated->set_sensitive(true); - saturated->setValue (pp->vibrance.saturated); // Pastels and Saturated are separate - } - skinTonesCurve->setCurve (pp->vibrance.skintonescurve); - - enableListener (); -} - -void Vibrance::autoOpenCurve () { - skinTonesCurve->openIfNonlinear(); -} - -void Vibrance::write( ProcParams* pp, ParamsEdited* pedited) { - pp->vibrance.enabled = getEnabled (); - pp->vibrance.pastels = pastels->getIntValue(); - pp->vibrance.saturated = pastSatTog->get_active() ? pp->vibrance.pastels : saturated->getIntValue (); - pp->vibrance.psthreshold = psThreshold->getValue (); - pp->vibrance.protectskins = protectSkins->get_active (); - pp->vibrance.avoidcolorshift = avoidColorShift->get_active (); - pp->vibrance.pastsattog = pastSatTog->get_active (); - pp->vibrance.skintonescurve = skinTonesCurve->getCurve (); - - if (pedited) { - pedited->vibrance.enabled = !get_inconsistent(); - pedited->vibrance.pastels = pastels->getEditedState (); - pedited->vibrance.saturated = saturated->getEditedState (); - pedited->vibrance.psthreshold = psThreshold->getEditedState (); - pedited->vibrance.protectskins = !protectSkins->get_inconsistent(); - pedited->vibrance.avoidcolorshift = !avoidColorShift->get_inconsistent(); - pedited->vibrance.pastsattog = !pastSatTog->get_inconsistent(); - pedited->vibrance.skintonescurve = !skinTonesCurve->isUnChanged (); - } - -} -void Vibrance::curveChanged () { - - if (listener && getEnabled ()) listener->panelChanged (EvVibranceSkinTonesCurve, M("HISTORY_CUSTOMCURVE")); -} - -void Vibrance::enabledChanged () { - if (listener) { - if (get_inconsistent()) - listener->panelChanged (EvVibranceEnabled, M("GENERAL_UNCHANGED")); - if (getEnabled()) - listener->panelChanged (EvVibranceEnabled, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvVibranceEnabled, M("GENERAL_DISABLED")); - } -} - -void Vibrance::protectskins_toggled () { - if (batchMode) { - if (protectSkins->get_inconsistent()) { - protectSkins->set_inconsistent (false); - pskinsconn.block (true); - protectSkins->set_active (false); - pskinsconn.block (false); - } - else if (lastProtectSkins) - protectSkins->set_inconsistent (true); - - lastProtectSkins = protectSkins->get_active (); - } - - if (listener && getEnabled()) { - if (protectSkins->get_active ()) - listener->panelChanged (EvVibranceProtectSkins, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvVibranceProtectSkins, M("GENERAL_DISABLED")); - } -} - -void Vibrance::avoidcolorshift_toggled () { - if (batchMode) { - if (avoidColorShift->get_inconsistent()) { - avoidColorShift->set_inconsistent (false); - ashiftconn.block (true); - avoidColorShift->set_active (false); - ashiftconn.block (false); - } - else if (lastAvoidColorShift) - avoidColorShift->set_inconsistent (true); - - lastAvoidColorShift = avoidColorShift->get_active (); - } - - if (listener && getEnabled()) { - if (avoidColorShift->get_active ()) - listener->panelChanged (EvVibranceAvoidColorShift, M("GENERAL_ENABLED")); - else - listener->panelChanged (EvVibranceAvoidColorShift, M("GENERAL_DISABLED")); - } -} - -void Vibrance::pastsattog_toggled () { - if (batchMode) { - if (pastSatTog->get_inconsistent()) { - pastSatTog->set_inconsistent (false); - pastsattogconn.block (true); - pastSatTog->set_active (false); - pastsattogconn.block (false); - } - else if (lastPastSatTog) - pastSatTog->set_inconsistent (true); - - lastPastSatTog = pastSatTog->get_active (); - } - - if (pastSatTog->get_active()) { - // Link both slider, so we set saturated and psThresholds unsensitive - psThreshold->set_sensitive(false); - saturated->set_sensitive(false); - saturated->setValue (pastels->getValue()); // Pastels and Saturated are linked - } - else { - // Separate sliders, so we set saturated and psThresholds sensitive again - psThreshold->set_sensitive(true); - saturated->set_sensitive(true); - } - - if (listener && getEnabled()) { - if (pastSatTog->get_active ()) { - listener->panelChanged (EvVibrancePastSatTog, M("GENERAL_ENABLED")); - } - else - listener->panelChanged (EvVibrancePastSatTog, M("GENERAL_DISABLED")); - } -} - -void Vibrance::adjusterChanged (Adjuster* a, double newval) { - if (a == pastels && pastSatTog->get_active()) - saturated->setValue (newval); - - if (listener && getEnabled()) { - Glib::ustring value = a->getTextValue(); - - if (a == pastels ) - listener->panelChanged (EvVibrancePastels, value ); - else if (a == saturated && !pastSatTog->get_active()) - listener->panelChanged (EvVibranceSaturated, value ); - } -} - -void Vibrance::adjusterChanged (ThresholdAdjuster* a, int newBottom, int newTop) { - if (listener && getEnabled()) { - listener->panelChanged (EvVibrancePastSatThreshold, psThreshold->getHistoryString()); - } -} - - -void Vibrance::setBatchMode(bool batchMode) { - - ToolPanel::setBatchMode (batchMode); - - pastels->showEditedCB (); - saturated->showEditedCB (); - psThreshold->showEditedCB (); - - curveEditorGG->setBatchMode (batchMode); -} - -void Vibrance::setDefaults(const ProcParams* defParams, const ParamsEdited* pedited) { - pastels->setDefault (defParams->vibrance.pastels); - saturated->setDefault (defParams->vibrance.saturated); - psThreshold->setDefault (defParams->vibrance.psthreshold); - - if (pedited) { - pastels->setDefaultEditedState (pedited->vibrance.pastels ? Edited : UnEdited); - saturated->setDefaultEditedState (pedited->vibrance.saturated ? Edited : UnEdited); - psThreshold->setDefaultEditedState (pedited->vibrance.psthreshold ? Edited : UnEdited); - - } else { - pastels->setDefaultEditedState (Irrelevant); - saturated->setDefaultEditedState (Irrelevant); - psThreshold->setDefaultEditedState (Irrelevant); - } -} - -void Vibrance::setAdjusterBehavior (bool pastelsadd, bool saturatedadd) { - pastels->setAddMode (pastelsadd); - saturated->setAddMode (saturatedadd); -} - -void Vibrance::trimValues (ProcParams* pp) { - pastels->trimValue (pp->vibrance.pastels); - saturated->trimValue (pp->vibrance.saturated); -} - -std::vector Vibrance::getCurvePoints(ThresholdSelector* tAdjuster) const { - std::vector points; - double threshold, transitionWeighting; - tAdjuster->getPositions(transitionWeighting, threshold); // ( range -100;+100, range 0;+100 ) - transitionWeighting /= 100.; // range -1., +1. - threshold /= 100.; // range 0., +1. - - // Initial point - points.push_back(0.); points.push_back(0.); - - double p2 = 3.0*threshold/4.0; // same one than in ipvibrance.cc - double s0 = threshold + (1.0-threshold)/4.0; // same one than in ipvibrance.cc - - // point at the beginning of the first linear transition - points.push_back(p2); points.push_back(0.); - - // Y value of the chroma mean point, calculated to get a straight line between p2 and s0 - double chromaMean = (threshold/4.0) / (s0-p2); - // move chromaMean up or down depending on transitionWeighting - if (transitionWeighting > 0.0) { - // positive values -> give more weight to Saturated - chromaMean = (1.0-chromaMean) * transitionWeighting + chromaMean; - } - else if (transitionWeighting < 0.0) { - // negative values -> give more weight to Pastels - chromaMean = chromaMean * transitionWeighting + chromaMean; - } - - // point at the location of the Top cursor, at the end of the first linear transition and the beginning of the second one - points.push_back(threshold); points.push_back(chromaMean); - - if (threshold < 1.0) { - - // point at the end of the second linear transition - points.push_back(s0); points.push_back(1.0); - - // end point - points.push_back(1.0); points.push_back(1.0); - } - - return points; -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "vibrance.h" +#include "../rtengine/color.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +Vibrance::Vibrance () : FoldableToolPanel(this, "vibrance", M("TP_VIBRANCE_LABEL"), false, true) { + + std::vector milestones; + float R, G, B; + // -0.1 rad < Hue < 1.6 rad + Color::hsv2rgb01(0.92f, 0.45f, 0.6f, R, G, B); + milestones.push_back( GradientMilestone(0.0, double(R), double(G), double(B)) ); + Color::hsv2rgb01(0.14056f, 0.45f, 0.6f, R, G, B); + milestones.push_back( GradientMilestone(1.0, double(R), double(G), double(B)) ); + + saturated = Gtk::manage(new Adjuster (M("TP_VIBRANCE_SATURATED"),-100.,100.,1.,0.)); + saturated->setAdjusterListener (this); + saturated->set_sensitive(false); + //if (saturated->delay < 1000) saturated->delay = 1000; + pack_start( *saturated, Gtk::PACK_SHRINK, 0); + + pastels = Gtk::manage(new Adjuster (M("TP_VIBRANCE_PASTELS"),-100.,100.,1.,0.)); + pastels->setAdjusterListener (this); + //if (pastels->delay < 1000) pastels->delay = 1000; + pack_start( *pastels, Gtk::PACK_SHRINK, 0); + + psThreshold = Gtk::manage (new ThresholdAdjuster (M("TP_VIBRANCE_PSTHRESHOLD"), -100., 100., 0., M("TP_VIBRANCE_PSTHRESHOLD_WEIGTHING"), 0, 0., 100., 75., M("TP_VIBRANCE_PSTHRESHOLD_SATTHRESH"), 0, this, false)); + psThreshold->setAdjusterListener (this); + psThreshold->set_tooltip_markup(M("TP_VIBRANCE_PSTHRESHOLD_TOOLTIP")); + psThreshold->set_sensitive(false); + //if (psThreshold->delay < 1000) psThreshold->delay = 1000; + pack_start( *psThreshold, Gtk::PACK_SHRINK, 0); + + protectSkins = Gtk::manage (new Gtk::CheckButton (M("TP_VIBRANCE_PROTECTSKINS"))); + protectSkins->set_active (true); + pack_start(*protectSkins, Gtk::PACK_SHRINK, 0); + + avoidColorShift = Gtk::manage (new Gtk::CheckButton (M("TP_VIBRANCE_AVOIDCOLORSHIFT"))); + avoidColorShift->set_active (true); + pack_start(*avoidColorShift, Gtk::PACK_SHRINK, 0); + + pastSatTog = Gtk::manage (new Gtk::CheckButton (M("TP_VIBRANCE_PASTSATTOG"))); + pastSatTog->set_active (true); + pack_start(*pastSatTog, Gtk::PACK_SHRINK, 0); + + curveEditorGG = new CurveEditorGroup (options.lastVibranceCurvesDir, M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_LABEL")); + curveEditorGG->setCurveListener (this); + + skinTonesCurve = static_cast(curveEditorGG->addCurve(CT_Diagonal, M("TP_VIBRANCE_CURVEEDITOR_SKINTONES"))); + skinTonesCurve->setTooltip(M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_TOOLTIP")); + skinTonesCurve->setBottomBarBgGradient(milestones); + skinTonesCurve->setLeftBarBgGradient(milestones); + skinTonesCurve->setRangeLabels( + M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE1"), M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE2"), + M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE3"), M("TP_VIBRANCE_CURVEEDITOR_SKINTONES_RANGE4") + ); + skinTonesCurve->setRangeDefaultMilestones(0.1, 0.4, 0.85); + curveEditorGG->curveListComplete(); + + pack_start (*curveEditorGG, Gtk::PACK_SHRINK, 4); + + show (); + + pskinsconn = protectSkins->signal_toggled().connect( sigc::mem_fun(*this, &Vibrance::protectskins_toggled) ); + ashiftconn = avoidColorShift->signal_toggled().connect( sigc::mem_fun(*this, &Vibrance::avoidcolorshift_toggled) ); + pastsattogconn = pastSatTog->signal_toggled().connect( sigc::mem_fun(*this, &Vibrance::pastsattog_toggled) ); +} + +Vibrance::~Vibrance () { + delete curveEditorGG; +} + +void Vibrance::read(const ProcParams* pp, const ParamsEdited* pedited) { + disableListener (); + + if(pedited ){ + set_inconsistent (multiImage && !pedited->vibrance.enabled); + pastels->setEditedState (pedited->vibrance.pastels ? Edited : UnEdited); + saturated->setEditedState (pedited->vibrance.saturated ? Edited : UnEdited); + psThreshold->setEditedState (pedited->vibrance.psthreshold ? Edited : UnEdited); + protectSkins->set_inconsistent (!pedited->vibrance.protectskins); + avoidColorShift->set_inconsistent (!pedited->vibrance.avoidcolorshift); + pastSatTog->set_inconsistent (!pedited->vibrance.pastsattog); + skinTonesCurve->setUnChanged (!pedited->vibrance.skintonescurve); + } + + setEnabled (pp->vibrance.enabled); + + pskinsconn.block (true); + protectSkins->set_active (pp->vibrance.protectskins); + pskinsconn.block (false); + lastProtectSkins = pp->vibrance.protectskins; + + ashiftconn.block (true); + avoidColorShift->set_active (pp->vibrance.avoidcolorshift); + ashiftconn.block (false); + lastAvoidColorShift = pp->vibrance.avoidcolorshift; + + pastsattogconn.block (true); + pastSatTog->set_active (pp->vibrance.pastsattog); + pastsattogconn.block (false); + lastPastSatTog = pp->vibrance.pastsattog; + + pastels->setValue (pp->vibrance.pastels); + psThreshold->setValue (pp->vibrance.psthreshold); + + if (lastPastSatTog) { + // Link both slider, so we set saturated and psThresholds unsensitive + psThreshold->set_sensitive(false); + saturated->set_sensitive(false); + saturated->setValue (pp->vibrance.pastels); // Pastels and Saturated are linked + } + else { + // Separate sliders, so we set saturated and psThresholds sensitive again + psThreshold->set_sensitive(true); + saturated->set_sensitive(true); + saturated->setValue (pp->vibrance.saturated); // Pastels and Saturated are separate + } + skinTonesCurve->setCurve (pp->vibrance.skintonescurve); + + enableListener (); +} + +void Vibrance::autoOpenCurve () { + skinTonesCurve->openIfNonlinear(); +} + +void Vibrance::write( ProcParams* pp, ParamsEdited* pedited) { + pp->vibrance.enabled = getEnabled (); + pp->vibrance.pastels = pastels->getIntValue(); + pp->vibrance.saturated = pastSatTog->get_active() ? pp->vibrance.pastels : saturated->getIntValue (); + pp->vibrance.psthreshold = psThreshold->getValue (); + pp->vibrance.protectskins = protectSkins->get_active (); + pp->vibrance.avoidcolorshift = avoidColorShift->get_active (); + pp->vibrance.pastsattog = pastSatTog->get_active (); + pp->vibrance.skintonescurve = skinTonesCurve->getCurve (); + + if (pedited) { + pedited->vibrance.enabled = !get_inconsistent(); + pedited->vibrance.pastels = pastels->getEditedState (); + pedited->vibrance.saturated = saturated->getEditedState (); + pedited->vibrance.psthreshold = psThreshold->getEditedState (); + pedited->vibrance.protectskins = !protectSkins->get_inconsistent(); + pedited->vibrance.avoidcolorshift = !avoidColorShift->get_inconsistent(); + pedited->vibrance.pastsattog = !pastSatTog->get_inconsistent(); + pedited->vibrance.skintonescurve = !skinTonesCurve->isUnChanged (); + } + +} +void Vibrance::curveChanged () { + + if (listener && getEnabled ()) listener->panelChanged (EvVibranceSkinTonesCurve, M("HISTORY_CUSTOMCURVE")); +} + +void Vibrance::enabledChanged () { + if (listener) { + if (get_inconsistent()) + listener->panelChanged (EvVibranceEnabled, M("GENERAL_UNCHANGED")); + if (getEnabled()) + listener->panelChanged (EvVibranceEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvVibranceEnabled, M("GENERAL_DISABLED")); + } +} + +void Vibrance::protectskins_toggled () { + if (batchMode) { + if (protectSkins->get_inconsistent()) { + protectSkins->set_inconsistent (false); + pskinsconn.block (true); + protectSkins->set_active (false); + pskinsconn.block (false); + } + else if (lastProtectSkins) + protectSkins->set_inconsistent (true); + + lastProtectSkins = protectSkins->get_active (); + } + + if (listener && getEnabled()) { + if (protectSkins->get_active ()) + listener->panelChanged (EvVibranceProtectSkins, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvVibranceProtectSkins, M("GENERAL_DISABLED")); + } +} + +void Vibrance::avoidcolorshift_toggled () { + if (batchMode) { + if (avoidColorShift->get_inconsistent()) { + avoidColorShift->set_inconsistent (false); + ashiftconn.block (true); + avoidColorShift->set_active (false); + ashiftconn.block (false); + } + else if (lastAvoidColorShift) + avoidColorShift->set_inconsistent (true); + + lastAvoidColorShift = avoidColorShift->get_active (); + } + + if (listener && getEnabled()) { + if (avoidColorShift->get_active ()) + listener->panelChanged (EvVibranceAvoidColorShift, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvVibranceAvoidColorShift, M("GENERAL_DISABLED")); + } +} + +void Vibrance::pastsattog_toggled () { + if (batchMode) { + if (pastSatTog->get_inconsistent()) { + pastSatTog->set_inconsistent (false); + pastsattogconn.block (true); + pastSatTog->set_active (false); + pastsattogconn.block (false); + } + else if (lastPastSatTog) + pastSatTog->set_inconsistent (true); + + lastPastSatTog = pastSatTog->get_active (); + } + + if (pastSatTog->get_active()) { + // Link both slider, so we set saturated and psThresholds unsensitive + psThreshold->set_sensitive(false); + saturated->set_sensitive(false); + saturated->setValue (pastels->getValue()); // Pastels and Saturated are linked + } + else { + // Separate sliders, so we set saturated and psThresholds sensitive again + psThreshold->set_sensitive(true); + saturated->set_sensitive(true); + } + + if (listener && getEnabled()) { + if (pastSatTog->get_active ()) { + listener->panelChanged (EvVibrancePastSatTog, M("GENERAL_ENABLED")); + } + else + listener->panelChanged (EvVibrancePastSatTog, M("GENERAL_DISABLED")); + } +} + +void Vibrance::adjusterChanged (Adjuster* a, double newval) { + if (a == pastels && pastSatTog->get_active()) + saturated->setValue (newval); + + if (listener && getEnabled()) { + Glib::ustring value = a->getTextValue(); + + if (a == pastels ) + listener->panelChanged (EvVibrancePastels, value ); + else if (a == saturated && !pastSatTog->get_active()) + listener->panelChanged (EvVibranceSaturated, value ); + } +} + +void Vibrance::adjusterChanged (ThresholdAdjuster* a, int newBottom, int newTop) { + if (listener && getEnabled()) { + listener->panelChanged (EvVibrancePastSatThreshold, psThreshold->getHistoryString()); + } +} + + +void Vibrance::setBatchMode(bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + + pastels->showEditedCB (); + saturated->showEditedCB (); + psThreshold->showEditedCB (); + + curveEditorGG->setBatchMode (batchMode); +} + +void Vibrance::setDefaults(const ProcParams* defParams, const ParamsEdited* pedited) { + pastels->setDefault (defParams->vibrance.pastels); + saturated->setDefault (defParams->vibrance.saturated); + psThreshold->setDefault (defParams->vibrance.psthreshold); + + if (pedited) { + pastels->setDefaultEditedState (pedited->vibrance.pastels ? Edited : UnEdited); + saturated->setDefaultEditedState (pedited->vibrance.saturated ? Edited : UnEdited); + psThreshold->setDefaultEditedState (pedited->vibrance.psthreshold ? Edited : UnEdited); + + } else { + pastels->setDefaultEditedState (Irrelevant); + saturated->setDefaultEditedState (Irrelevant); + psThreshold->setDefaultEditedState (Irrelevant); + } +} + +void Vibrance::setAdjusterBehavior (bool pastelsadd, bool saturatedadd) { + pastels->setAddMode (pastelsadd); + saturated->setAddMode (saturatedadd); +} + +void Vibrance::trimValues (ProcParams* pp) { + pastels->trimValue (pp->vibrance.pastels); + saturated->trimValue (pp->vibrance.saturated); +} + +std::vector Vibrance::getCurvePoints(ThresholdSelector* tAdjuster) const { + std::vector points; + double threshold, transitionWeighting; + tAdjuster->getPositions(transitionWeighting, threshold); // ( range -100;+100, range 0;+100 ) + transitionWeighting /= 100.; // range -1., +1. + threshold /= 100.; // range 0., +1. + + // Initial point + points.push_back(0.); points.push_back(0.); + + double p2 = 3.0*threshold/4.0; // same one than in ipvibrance.cc + double s0 = threshold + (1.0-threshold)/4.0; // same one than in ipvibrance.cc + + // point at the beginning of the first linear transition + points.push_back(p2); points.push_back(0.); + + // Y value of the chroma mean point, calculated to get a straight line between p2 and s0 + double chromaMean = (threshold/4.0) / (s0-p2); + // move chromaMean up or down depending on transitionWeighting + if (transitionWeighting > 0.0) { + // positive values -> give more weight to Saturated + chromaMean = (1.0-chromaMean) * transitionWeighting + chromaMean; + } + else if (transitionWeighting < 0.0) { + // negative values -> give more weight to Pastels + chromaMean = chromaMean * transitionWeighting + chromaMean; + } + + // point at the location of the Top cursor, at the end of the first linear transition and the beginning of the second one + points.push_back(threshold); points.push_back(chromaMean); + + if (threshold < 1.0) { + + // point at the end of the second linear transition + points.push_back(s0); points.push_back(1.0); + + // end point + points.push_back(1.0); points.push_back(1.0); + } + + return points; +} diff --git a/rtgui/vibrance.h b/rtgui/vibrance.h index 4c58f34f5..699912d5c 100644 --- a/rtgui/vibrance.h +++ b/rtgui/vibrance.h @@ -1,76 +1,76 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _VIBRANCE_ -#define _VIBRANCE_ - -#include -#include "adjuster.h" -#include "thresholdadjuster.h" -#include "curveeditor.h" -#include "curveeditorgroup.h" -#include "toolpanel.h" - -class Vibrance : public ToolParamBlock, public AdjusterListener, public ThresholdCurveProvider, public ThresholdAdjusterListener, - public FoldableToolPanel, public CurveListener -{ - -protected: - CurveEditorGroup* curveEditorGG; - - Adjuster* pastels; - Adjuster* saturated; - ThresholdAdjuster* psThreshold; - Gtk::CheckButton* protectSkins; - Gtk::CheckButton* avoidColorShift; - Gtk::CheckButton* pastSatTog; - DiagonalCurveEditor* skinTonesCurve; - - bool lastProtectSkins; - bool lastAvoidColorShift; - bool lastPastSatTog; - - sigc::connection pskinsconn; - sigc::connection ashiftconn; - sigc::connection pastsattogconn; - -public: - - Vibrance (); - ~Vibrance (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void trimValues (rtengine::procparams::ProcParams* pp); - void setAdjusterBehavior (bool pastelsadd, bool saturatedadd); - void adjusterChanged (Adjuster* a, double newval); - void adjusterChanged (ThresholdAdjuster* a, int newBottom, int newTop); - void curveChanged (); - void autoOpenCurve (); - - void enabledChanged (); - void protectskins_toggled (); - void avoidcolorshift_toggled (); - void pastsattog_toggled (); - std::vector getCurvePoints(ThresholdSelector* tAdjuster) const; -}; - - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _VIBRANCE_ +#define _VIBRANCE_ + +#include +#include "adjuster.h" +#include "thresholdadjuster.h" +#include "curveeditor.h" +#include "curveeditorgroup.h" +#include "toolpanel.h" + +class Vibrance : public ToolParamBlock, public AdjusterListener, public ThresholdCurveProvider, public ThresholdAdjusterListener, + public FoldableToolPanel, public CurveListener +{ + +protected: + CurveEditorGroup* curveEditorGG; + + Adjuster* pastels; + Adjuster* saturated; + ThresholdAdjuster* psThreshold; + Gtk::CheckButton* protectSkins; + Gtk::CheckButton* avoidColorShift; + Gtk::CheckButton* pastSatTog; + DiagonalCurveEditor* skinTonesCurve; + + bool lastProtectSkins; + bool lastAvoidColorShift; + bool lastPastSatTog; + + sigc::connection pskinsconn; + sigc::connection ashiftconn; + sigc::connection pastsattogconn; + +public: + + Vibrance (); + ~Vibrance (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void trimValues (rtengine::procparams::ProcParams* pp); + void setAdjusterBehavior (bool pastelsadd, bool saturatedadd); + void adjusterChanged (Adjuster* a, double newval); + void adjusterChanged (ThresholdAdjuster* a, int newBottom, int newTop); + void curveChanged (); + void autoOpenCurve (); + + void enabledChanged (); + void protectskins_toggled (); + void avoidcolorshift_toggled (); + void pastsattog_toggled (); + std::vector getCurvePoints(ThresholdSelector* tAdjuster) const; +}; + + +#endif diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 2cd3a8057..2b028e657 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -1,132 +1,132 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "xtransprocess.h" -#include "options.h" -#include "guiutils.h" -using namespace rtengine; -using namespace rtengine::procparams; - -XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP_RAW_LABEL"), true) -{ - Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); - hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4); - method = Gtk::manage (new MyComboBoxText ()); - for( size_t i=0; iappend_text(procparams::RAWParams::XTransSensor::methodstring[i]); - - method->set_active(0); - hb1->set_tooltip_markup (M("TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP")); - - hb1->pack_end (*method, Gtk::PACK_EXPAND_WIDGET, 4); - pack_start( *hb1, Gtk::PACK_SHRINK, 4); - - pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); - ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"),0,5,1,0 )); - ccSteps->setAdjusterListener (this); - if (ccSteps->delay < 1000) ccSteps->delay = 1000; - ccSteps->show(); - pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); - - methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &XTransProcess::methodChanged) ); -} - - -void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - methodconn.block (true); - - method->set_active(procparams::RAWParams::XTransSensor::numMethods); - for( size_t i=0; i< procparams::RAWParams::XTransSensor::numMethods; i++) - if( pp->raw.xtranssensor.method == procparams::RAWParams::XTransSensor::methodstring[i]) { - method->set_active(i); - oldSelection = i; - break; - } - - if(pedited ){ - ccSteps->setEditedState (pedited->raw.xtranssensor.ccSteps ? Edited : UnEdited); - if( !pedited->raw.xtranssensor.method ) - method->set_active(procparams::RAWParams::XTransSensor::numMethods); // No name - } - - ccSteps->setValue (pp->raw.xtranssensor.ccSteps); - - methodconn.block (false); - - enableListener (); -} - -void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.xtranssensor.ccSteps = ccSteps->getIntValue(); - - int currentRow = method->get_active_row_number(); - if( currentRow>=0 && currentRow < procparams::RAWParams::XTransSensor::numMethods) - pp->raw.xtranssensor.method = procparams::RAWParams::XTransSensor::methodstring[currentRow]; - - if (pedited) { - pedited->raw.xtranssensor.method = method->get_active_row_number() != procparams::RAWParams::XTransSensor::numMethods; - pedited->raw.xtranssensor.ccSteps = ccSteps->getEditedState (); - } -} - -void XTransProcess::setBatchMode(bool batchMode) -{ - method->append_text (M("GENERAL_UNCHANGED")); - method->set_active(procparams::RAWParams::XTransSensor::numMethods); // No name - ToolPanel::setBatchMode (batchMode); - ccSteps->showEditedCB (); -} - -void XTransProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) -{ - ccSteps->setDefault (defParams->raw.xtranssensor.ccSteps); - if (pedited) { - ccSteps->setDefaultEditedState(pedited->raw.xtranssensor.ccSteps ? Edited : UnEdited); - }else{ - ccSteps->setDefaultEditedState(Irrelevant ); - } -} - -void XTransProcess::adjusterChanged (Adjuster* a, double newval) -{ - if (listener) { - if (a == ccSteps) - listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); - } -} - -void XTransProcess::methodChanged () -{ - int curSelection = method->get_active_row_number(); - - Glib::ustring methodName=""; - bool ppreq = false; - if( curSelection>=0 && curSelection < procparams::RAWParams::XTransSensor::numMethods) { - methodName = procparams::RAWParams::XTransSensor::methodstring[curSelection]; - if (curSelection == procparams::RAWParams::XTransSensor::mono || oldSelection == procparams::RAWParams::XTransSensor::mono) { - ppreq = true; - } - } - oldSelection = curSelection; - - if (listener) - listener->panelChanged (ppreq ? EvDemosaicMethodPreProc : EvDemosaicMethod, methodName); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "xtransprocess.h" +#include "options.h" +#include "guiutils.h" +using namespace rtengine; +using namespace rtengine::procparams; + +XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP_RAW_LABEL"), true) +{ + Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); + hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4); + method = Gtk::manage (new MyComboBoxText ()); + for( size_t i=0; iappend_text(procparams::RAWParams::XTransSensor::methodstring[i]); + + method->set_active(0); + hb1->set_tooltip_markup (M("TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP")); + + hb1->pack_end (*method, Gtk::PACK_EXPAND_WIDGET, 4); + pack_start( *hb1, Gtk::PACK_SHRINK, 4); + + pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); + ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"),0,5,1,0 )); + ccSteps->setAdjusterListener (this); + if (ccSteps->delay < 1000) ccSteps->delay = 1000; + ccSteps->show(); + pack_start( *ccSteps, Gtk::PACK_SHRINK, 4); + + methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &XTransProcess::methodChanged) ); +} + + +void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + methodconn.block (true); + + method->set_active(procparams::RAWParams::XTransSensor::numMethods); + for( size_t i=0; i< procparams::RAWParams::XTransSensor::numMethods; i++) + if( pp->raw.xtranssensor.method == procparams::RAWParams::XTransSensor::methodstring[i]) { + method->set_active(i); + oldSelection = i; + break; + } + + if(pedited ){ + ccSteps->setEditedState (pedited->raw.xtranssensor.ccSteps ? Edited : UnEdited); + if( !pedited->raw.xtranssensor.method ) + method->set_active(procparams::RAWParams::XTransSensor::numMethods); // No name + } + + ccSteps->setValue (pp->raw.xtranssensor.ccSteps); + + methodconn.block (false); + + enableListener (); +} + +void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.xtranssensor.ccSteps = ccSteps->getIntValue(); + + int currentRow = method->get_active_row_number(); + if( currentRow>=0 && currentRow < procparams::RAWParams::XTransSensor::numMethods) + pp->raw.xtranssensor.method = procparams::RAWParams::XTransSensor::methodstring[currentRow]; + + if (pedited) { + pedited->raw.xtranssensor.method = method->get_active_row_number() != procparams::RAWParams::XTransSensor::numMethods; + pedited->raw.xtranssensor.ccSteps = ccSteps->getEditedState (); + } +} + +void XTransProcess::setBatchMode(bool batchMode) +{ + method->append_text (M("GENERAL_UNCHANGED")); + method->set_active(procparams::RAWParams::XTransSensor::numMethods); // No name + ToolPanel::setBatchMode (batchMode); + ccSteps->showEditedCB (); +} + +void XTransProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + ccSteps->setDefault (defParams->raw.xtranssensor.ccSteps); + if (pedited) { + ccSteps->setDefaultEditedState(pedited->raw.xtranssensor.ccSteps ? Edited : UnEdited); + }else{ + ccSteps->setDefaultEditedState(Irrelevant ); + } +} + +void XTransProcess::adjusterChanged (Adjuster* a, double newval) +{ + if (listener) { + if (a == ccSteps) + listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); + } +} + +void XTransProcess::methodChanged () +{ + int curSelection = method->get_active_row_number(); + + Glib::ustring methodName=""; + bool ppreq = false; + if( curSelection>=0 && curSelection < procparams::RAWParams::XTransSensor::numMethods) { + methodName = procparams::RAWParams::XTransSensor::methodstring[curSelection]; + if (curSelection == procparams::RAWParams::XTransSensor::mono || oldSelection == procparams::RAWParams::XTransSensor::mono) { + ppreq = true; + } + } + oldSelection = curSelection; + + if (listener) + listener->panelChanged (ppreq ? EvDemosaicMethodPreProc : EvDemosaicMethod, methodName); +} diff --git a/rtgui/xtransprocess.h b/rtgui/xtransprocess.h index ad83ffaad..4ee468a27 100644 --- a/rtgui/xtransprocess.h +++ b/rtgui/xtransprocess.h @@ -1,51 +1,51 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _XTRANSPROCESS_H_ -#define _XTRANSPROCESS_H_ - -#include -#include "adjuster.h" -#include "guiutils.h" -#include "toolpanel.h" - - -class XTransProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel{ - - protected: - - MyComboBoxText* method; - Adjuster* ccSteps; - - int oldSelection; - sigc::connection methodconn; - - public: - - XTransProcess (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - - void methodChanged (); - void adjusterChanged (Adjuster* a, double newval); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _XTRANSPROCESS_H_ +#define _XTRANSPROCESS_H_ + +#include +#include "adjuster.h" +#include "guiutils.h" +#include "toolpanel.h" + + +class XTransProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel{ + + protected: + + MyComboBoxText* method; + Adjuster* ccSteps; + + int oldSelection; + sigc::connection methodconn; + + public: + + XTransProcess (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + + void methodChanged (); + void adjusterChanged (Adjuster* a, double newval); +}; + +#endif diff --git a/rtgui/xtransrawexposure.cc b/rtgui/xtransrawexposure.cc index 458647ac1..fa86a4014 100644 --- a/rtgui/xtransrawexposure.cc +++ b/rtgui/xtransrawexposure.cc @@ -1,131 +1,131 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "xtransrawexposure.h" -#include "guiutils.h" -#include "../rtengine/safegtk.h" -#include - -using namespace rtengine; -using namespace rtengine::procparams; - -XTransRAWExposure::XTransRAWExposure () : FoldableToolPanel(this, "xtransrawexposure", M("TP_EXPOS_BLACKPOINT_LABEL")) -{ - PexBlackRed = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_RED"),-2048,2048,0.1,0));//black level - PexBlackRed->setAdjusterListener (this); - if (PexBlackRed->delay < 1000) PexBlackRed->delay = 1000; - PexBlackRed->show(); - PexBlackGreen = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_GREEN"),-2048,2048,0.1,0));//black level - PexBlackGreen->setAdjusterListener (this); - if (PexBlackGreen->delay < 1000) PexBlackGreen->delay = 1000; - PexBlackGreen->show(); - PexBlackBlue = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_BLUE"),-2048,2048,0.1,0));//black level - PexBlackBlue->setAdjusterListener (this); - if (PexBlackBlue->delay < 1000) PexBlackBlue->delay = 1000; - PexBlackBlue->show(); - - pack_start( *PexBlackRed, Gtk::PACK_SHRINK, 0);//black - pack_start( *PexBlackGreen, Gtk::PACK_SHRINK, 0);//black - pack_start( *PexBlackBlue, Gtk::PACK_SHRINK, 0);//black -} - -void XTransRAWExposure::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) -{ - disableListener (); - - if(pedited ){ - PexBlackRed->setEditedState( pedited->raw.xtranssensor.exBlackRed ? Edited : UnEdited ); - PexBlackGreen->setEditedState( pedited->raw.xtranssensor.exBlackGreen ? Edited : UnEdited ); - PexBlackBlue->setEditedState( pedited->raw.xtranssensor.exBlackBlue ? Edited : UnEdited ); - } - - PexBlackRed->setValue (pp->raw.xtranssensor.blackred);//black - PexBlackGreen->setValue (pp->raw.xtranssensor.blackgreen);//black - PexBlackBlue->setValue (pp->raw.xtranssensor.blackblue);//black - - enableListener (); -} - -void XTransRAWExposure::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) -{ - pp->raw.xtranssensor.blackred = PexBlackRed->getValue();// black - pp->raw.xtranssensor.blackgreen = PexBlackGreen->getValue();// black - pp->raw.xtranssensor.blackblue = PexBlackBlue->getValue();// black - - if (pedited) { - pedited->raw.xtranssensor.exBlackRed = PexBlackRed->getEditedState ();//black - pedited->raw.xtranssensor.exBlackGreen = PexBlackGreen->getEditedState ();//black - pedited->raw.xtranssensor.exBlackBlue = PexBlackBlue->getEditedState ();//black - } - -} - -void XTransRAWExposure::adjusterChanged (Adjuster* a, double newval) -{ - if (listener) { - Glib::ustring value = a->getTextValue(); - if (a == PexBlackRed) - listener->panelChanged (EvPreProcessExpBlackRed, value); - else if (a == PexBlackGreen) - listener->panelChanged (EvPreProcessExpBlackGreen, value); - else if (a == PexBlackBlue) - listener->panelChanged (EvPreProcessExpBlackBlue, value); - } -} - -void XTransRAWExposure::setBatchMode(bool batchMode) -{ - ToolPanel::setBatchMode (batchMode); - PexBlackRed->showEditedCB ();//black - PexBlackGreen->showEditedCB ();//black - PexBlackBlue->showEditedCB ();//black - -} - -void XTransRAWExposure::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) -{ - PexBlackRed->setDefault( defParams->raw.xtranssensor.blackred); - PexBlackGreen->setDefault( defParams->raw.xtranssensor.blackgreen); - PexBlackBlue->setDefault( defParams->raw.xtranssensor.blackblue); - - if (pedited) { - PexBlackRed->setDefaultEditedState( pedited->raw.xtranssensor.exBlackRed ? Edited : UnEdited); - PexBlackGreen->setDefaultEditedState( pedited->raw.xtranssensor.exBlackGreen ? Edited : UnEdited); - PexBlackBlue->setDefaultEditedState( pedited->raw.xtranssensor.exBlackBlue ? Edited : UnEdited); - - } else { - PexBlackRed->setDefaultEditedState( Irrelevant ); - PexBlackGreen->setDefaultEditedState( Irrelevant ); - PexBlackBlue->setDefaultEditedState( Irrelevant ); - - } -} - -void XTransRAWExposure::setAdjusterBehavior (bool pexblackadd) { - - PexBlackRed->setAddMode(pexblackadd); - PexBlackGreen->setAddMode(pexblackadd); - PexBlackBlue->setAddMode(pexblackadd); -} - -void XTransRAWExposure::trimValues (rtengine::procparams::ProcParams* pp) { - - PexBlackRed->trimValue(pp->raw.xtranssensor.blackred); - PexBlackGreen->trimValue(pp->raw.xtranssensor.blackgreen); - PexBlackBlue->trimValue(pp->raw.xtranssensor.blackblue); -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "xtransrawexposure.h" +#include "guiutils.h" +#include "../rtengine/safegtk.h" +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +XTransRAWExposure::XTransRAWExposure () : FoldableToolPanel(this, "xtransrawexposure", M("TP_EXPOS_BLACKPOINT_LABEL")) +{ + PexBlackRed = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_RED"),-2048,2048,0.1,0));//black level + PexBlackRed->setAdjusterListener (this); + if (PexBlackRed->delay < 1000) PexBlackRed->delay = 1000; + PexBlackRed->show(); + PexBlackGreen = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_GREEN"),-2048,2048,0.1,0));//black level + PexBlackGreen->setAdjusterListener (this); + if (PexBlackGreen->delay < 1000) PexBlackGreen->delay = 1000; + PexBlackGreen->show(); + PexBlackBlue = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_BLUE"),-2048,2048,0.1,0));//black level + PexBlackBlue->setAdjusterListener (this); + if (PexBlackBlue->delay < 1000) PexBlackBlue->delay = 1000; + PexBlackBlue->show(); + + pack_start( *PexBlackRed, Gtk::PACK_SHRINK, 0);//black + pack_start( *PexBlackGreen, Gtk::PACK_SHRINK, 0);//black + pack_start( *PexBlackBlue, Gtk::PACK_SHRINK, 0);//black +} + +void XTransRAWExposure::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + + if(pedited ){ + PexBlackRed->setEditedState( pedited->raw.xtranssensor.exBlackRed ? Edited : UnEdited ); + PexBlackGreen->setEditedState( pedited->raw.xtranssensor.exBlackGreen ? Edited : UnEdited ); + PexBlackBlue->setEditedState( pedited->raw.xtranssensor.exBlackBlue ? Edited : UnEdited ); + } + + PexBlackRed->setValue (pp->raw.xtranssensor.blackred);//black + PexBlackGreen->setValue (pp->raw.xtranssensor.blackgreen);//black + PexBlackBlue->setValue (pp->raw.xtranssensor.blackblue);//black + + enableListener (); +} + +void XTransRAWExposure::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) +{ + pp->raw.xtranssensor.blackred = PexBlackRed->getValue();// black + pp->raw.xtranssensor.blackgreen = PexBlackGreen->getValue();// black + pp->raw.xtranssensor.blackblue = PexBlackBlue->getValue();// black + + if (pedited) { + pedited->raw.xtranssensor.exBlackRed = PexBlackRed->getEditedState ();//black + pedited->raw.xtranssensor.exBlackGreen = PexBlackGreen->getEditedState ();//black + pedited->raw.xtranssensor.exBlackBlue = PexBlackBlue->getEditedState ();//black + } + +} + +void XTransRAWExposure::adjusterChanged (Adjuster* a, double newval) +{ + if (listener) { + Glib::ustring value = a->getTextValue(); + if (a == PexBlackRed) + listener->panelChanged (EvPreProcessExpBlackRed, value); + else if (a == PexBlackGreen) + listener->panelChanged (EvPreProcessExpBlackGreen, value); + else if (a == PexBlackBlue) + listener->panelChanged (EvPreProcessExpBlackBlue, value); + } +} + +void XTransRAWExposure::setBatchMode(bool batchMode) +{ + ToolPanel::setBatchMode (batchMode); + PexBlackRed->showEditedCB ();//black + PexBlackGreen->showEditedCB ();//black + PexBlackBlue->showEditedCB ();//black + +} + +void XTransRAWExposure::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) +{ + PexBlackRed->setDefault( defParams->raw.xtranssensor.blackred); + PexBlackGreen->setDefault( defParams->raw.xtranssensor.blackgreen); + PexBlackBlue->setDefault( defParams->raw.xtranssensor.blackblue); + + if (pedited) { + PexBlackRed->setDefaultEditedState( pedited->raw.xtranssensor.exBlackRed ? Edited : UnEdited); + PexBlackGreen->setDefaultEditedState( pedited->raw.xtranssensor.exBlackGreen ? Edited : UnEdited); + PexBlackBlue->setDefaultEditedState( pedited->raw.xtranssensor.exBlackBlue ? Edited : UnEdited); + + } else { + PexBlackRed->setDefaultEditedState( Irrelevant ); + PexBlackGreen->setDefaultEditedState( Irrelevant ); + PexBlackBlue->setDefaultEditedState( Irrelevant ); + + } +} + +void XTransRAWExposure::setAdjusterBehavior (bool pexblackadd) { + + PexBlackRed->setAddMode(pexblackadd); + PexBlackGreen->setAddMode(pexblackadd); + PexBlackBlue->setAddMode(pexblackadd); +} + +void XTransRAWExposure::trimValues (rtengine::procparams::ProcParams* pp) { + + PexBlackRed->trimValue(pp->raw.xtranssensor.blackred); + PexBlackGreen->trimValue(pp->raw.xtranssensor.blackgreen); + PexBlackBlue->trimValue(pp->raw.xtranssensor.blackblue); +} diff --git a/rtgui/xtransrawexposure.h b/rtgui/xtransrawexposure.h index 80f803406..c4708768b 100644 --- a/rtgui/xtransrawexposure.h +++ b/rtgui/xtransrawexposure.h @@ -1,49 +1,49 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef _XTRANSRAWEXPOSURE_H_ -#define _XTRANSRAWEXPOSURE_H_ - -#include -#include "adjuster.h" -#include "toolpanel.h" -#include "../rtengine/rawimage.h" - -class XTransRAWExposure : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { - -protected: - Adjuster* PexBlackRed; - Adjuster* PexBlackGreen; - Adjuster* PexBlackBlue; - -private: -// Gtk::CheckButton* PextwoGreen; -public: - - XTransRAWExposure (); - - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); - void setBatchMode (bool batchMode); - void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - void adjusterChanged (Adjuster* a, double newval); - void setAdjusterBehavior (bool pexblackadd); - void trimValues (rtengine::procparams::ProcParams* pp); -}; - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _XTRANSRAWEXPOSURE_H_ +#define _XTRANSRAWEXPOSURE_H_ + +#include +#include "adjuster.h" +#include "toolpanel.h" +#include "../rtengine/rawimage.h" + +class XTransRAWExposure : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { + +protected: + Adjuster* PexBlackRed; + Adjuster* PexBlackGreen; + Adjuster* PexBlackBlue; + +private: +// Gtk::CheckButton* PextwoGreen; +public: + + XTransRAWExposure (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void adjusterChanged (Adjuster* a, double newval); + void setAdjusterBehavior (bool pexblackadd); + void trimValues (rtengine::procparams::ProcParams* pp); +}; + +#endif diff --git a/tools/RTProfileBuilderSample.cs b/tools/RTProfileBuilderSample.cs index 8bfede8d0..81b724ab2 100644 --- a/tools/RTProfileBuilderSample.cs +++ b/tools/RTProfileBuilderSample.cs @@ -1,4 +1,4 @@ -#region Usings +#region Usings using System; using System.Text; using System.IO;